Swift语法基本总结

语言的基础部分

程序是指令的集合,写程序就是写一系列的指令去控制计算机去做我们想做的事情。
编译:将程序设计语言转换成计算机能够理解的机器语言或者某种中间代码的过程。

冯诺依曼体系结构的计算机:

  1. 使用二进制
  2. 程序存储执行

变量和常量

定义变量和常量是为了保存数据,变量和常量就是某种类型的值得存储空间。

var a: Int = 10
a = 100
var b: Int
b = 1000
var c = 1000

let d: Int = 10
// d = 100  // compiler error 编译错误
let e = 1000

说明:1. Swift有非常强大的类型推断,所以在定义变量时如果可以的话应该直接使用类型推断,不用手动指定类型;2. 如果可以的话应该尽可能使用常量而不是变量

语言元素

var a: Int = 10

关键字: 有特殊含义的单词.
标识符: 给变量、常量、函数、类、结构、协议、枚举、方法、属性等起的名字。
六条规则:

1.字母数字下划线,不能用数字进行开头
2.大小写敏感(区分大小写)
3.不能使用关键字做标识符
4.使用驼峰命名法(命名变量、常量、函数、方法、属性第一个单词小写,从第二个单词开始每个单词首字母大写:命名类、结构、协议、枚举每个单词首字母都要大写)
5.见名知意

  1. 命名私有的属性和方法时以下划线开头

运算符:Swift中的运算符其实都是函数

  1. 赋值运算符:=、+、-=、...
  2. 算术运算符:+、-、*、/、%
  3. 关系(比较)运算符:==、!=、<、<=、>、>=
  4. 逻辑运算符:&&、||、!
  5. 三元条件运算符:? :
  6. 其他运算符:[]、.、??、?、!、

字面(常)量:

  1. 整数字面量: 10、1_234_567、0x10、0o10=8、0b10=2
  2. 小数字面量: 123.45、1.2345e2=1.2345x10⑃2、0xab.cdp2
  3. 字符字面量: "e"、"\n"、"\u(41)"、"\u(e9)"
  4. 字符串字面量: "Hello"、"caf\u(e9)"
  5. 布尔字面量: true、false
  6. 空值字面量: nil
  7. 类型字面量: String.self(类型)、UILable.self

分隔符: 将不同的语言元素符号分开

说明:Swift中每个语句后面不用写分号,写代码时尽量保证一行只有一条语句这样就可以省略掉分号。

分支和循环

分支

  • if ...else:
下面代码实现了分段式函数求值
let x = 3.2
let y:Double
if x < -1 {
  y = 3 * x + 5
}
else if x <= 1{
    y = 5 * x - 3
}
else{
y = 7 * x + 1
}
print("f(\(x)) = \(y)")
  • switch case default:
下面代码实现了数字
 let score = 92.5
let level:String
switch score{
case 0..<60:
    level = "E"
case 60..<70:
    level = "D"
case 70..<80:
    level = "C"
case 80..<90:
    level = "B"
case 90..<100:
    level = "A"
default:
    level = "输入错误"
}
print(level)

例如:工资、摇色子

循环

下面实现了while ture循环 分鱼过程

  • while ture
 var total = 1
 while ture {
 var fish = total
 var isEnough = true 
 for _ in 1...5 {
  if(fish - 1) % 5 == 0 {
  fish = (fish - 1) / 5 * 4
  }
  else {
  isEnough = false
  break
  }
 }
 if isEnough {
 print(total)
 break
 }
 total += 1
 }
  • repeat...while
下面实现了repeat..while循环,对Hello.World做了一百次循环
repeat {
print("\(i).Hello.World!")
   i += 1
}
 while i <= 100
 ```





-  for...
```Swift
下面实现了For循环,99乘法表
for j in 1...99 {
print("9 * \(j) = \(9 * j)",terminator:"")
}

穷举法:穷尽所有可能性直到找到正确答案

下面程序实现了squot,例子"百钱白鸡"
 for x = 0...20 {
 for y = 0...33{
 let z = x - y 
 if 5 * x + 3 * y + z/3 == 100 && z % 3 == 0 {
 print("公鸡:\(x),母鸡:\(y),小鸡:\(z)")
                }
             }
         }

注意:在循环中可以使用break关键字来提前终止循环,也可以使用continue关键字使循环直接进入下一轮,但是应该尽量减少对break和continue的使用,因为它们不会让你的程序变得更好.

综合案例:craps赌博游戏
游戏规则:玩家摇色子,如果第一次摇出了7点或者11点,万家胜;如果摇出2,3或者12点,庄家胜;其他点数游戏继续。第二轮摇色子如果摇到7点,庄家胜,否则玩家继续摇色子直到分出胜负。

func roll() -> Int {
return Int(arc4random_uniform(6)) + 1
}
let firstPoint = roll() + roll()
print("玩家摇出了\(firstPoint)点")
var needsGoOn = false
case 7, 11: print("玩家胜")
case 2, 3, 12 : print("庄家胜!")
default: needsGoOn {
let currentPoint = roll() + roll()
print("玩家摇出了\(currentPoint)点")
if currenPoint == 7 {
print("庄家胜")
needsGoOn = false 
}
else if currentPoint = firstPoint {
print("万家胜")
isNeedsGoOn = false
           }

      }
}
switch firstPoint{}

容器

数组

  • 创建数组
var array1:[Int] = []
var array1: Array<Int> = []
var array2 = [1, 2, 3, 4, 5]
var array3 = [Int](coount: 5, repeatedValue: 0)
var array3 = Array<Int>(count:5, repeatedValue: 0)
  • 添加元素
 array1.append(2)
 array1.append(3)
 array1.append(1, atIndex:0)
 array1.insert(4, atIndex: array1.count)
 array1 += [5]
 array1 += [6, 7, 8]
  • 删除元素
array1.remove 
array1.removeFirst()
array1.removeLast()
array1.removerange(1...2)
array1.removeAll()
  • 修改元素
 array[0] = 100
 array3[array3.count - 1] = 500
 print(array3)

切记不能越界

  • 遍历数组

1.方式1:for 循环

for i in 0..<array3.count{
print(array3[i])
}

2.方式2:for..in循环

for temp in array3 {
print(temp)
}

注意: for-in循环是一个只读循环,也就意味着再循环的过程中不能对数组的元素进行修改

3.方式3:枚举循环

for (i, temp) in array3.enumerate() {
if i == 0 {
       array 3[i] = 1
}
print("\(i). \(temp)")
}

** 提醒:**操作数组时最重要的是不能操作越界去访问元素.数组对象的count属性表面了数组中有多少个元素,那么有效的索引(下标)范围是0到count-1

  • 数组中的元素也可以是数组,因此我们可以构造多维数组。最常见的是二维素
  • 数组,它相当于是一个有行有列的数组,数组中的每个元素代表一行,该数组中的每个元素代表行里面的列。二维数组可以模拟现实世界中的表格、矩阵、棋盘、2D格子类游戏的地图,所以在实际开发中使用的十分广泛
  • 用二维数组模拟表格的例子:
func randomInt(min: UInt32,max:UInt32) -> Int )
let namesArray = ["关羽", "张飞", "赵云", "马超", "黄忠"]
let ciyrsesArray = ["语文","数学","英语"]
var scoresArray = [[Double]](count: namesArray.count,
repeatedValue:[Double](count: coursesArray.count,
repeatedValue:0))
for i in 0..<scoresArray.count {
     for j in 0..<scoresArray[i].count{
         scoresArray[i][j] = Double(randomInt(0, max:100))
    }
}
for(index, array) in  scoresArray.enumerate(){
var sum = 0.0
for score in array {
sum += score
}
print("\(namesArray[index]的平均成绩为:\(avg)")
}
for i in 0..<coursesArray.count{}
var sum = 0.0
for row in 0..<scoresArray.count {
     sum += scoresArray[row][1]
    }
let avg = sum / Double(namesArray.count)
print("语文课的平均成绩为:\(avg)")
}

数组是使用联系的内存空间来保存

集合

集合在内存中是离散的,集合中的元素通过计算Hash Code(哈希码或散列码)来决定存放在内存中的什么位置,集合中不允许有重复元素

  • 创建集合
集合的遍历
  var set: Set<Int> = [1, 2, 1, 2, 3,200,55,44]
  set.insert(100) //添加元素insert 删除元素remove
  for temp in set {
       print(temp)
  }
  • 添加和删除元素
  • intersect 交集 union 并集 subtract 差集

字典(重要)

字典是以键值对的方式保存数据的容器.字典中的元素是键值对组合.通过键可以找到对应的值.

  • 创建字典 冒号前面是值得类型,冒号后面是键的类型
let dict:[Int:String] = [ 
  1:"Hello",
  2: "Good",
  3: "Wonderful",
  5: "delicious"
]
if let str = dict[1]
     print(str)
     }
     else{
     print("找不到")
     }
  • 添加元素和删除元素
  dict[4] = "Shit" 添加元素
  dict.count
  dict
dict[5] = nil 删除元素
removerValueForKey(5) 同上,但是更麻烦
dict[3] = "shamte" 修改

Int String Double 都是遵循了Hashable协议。

  • 遍历元素
第一种
for key in dict.keys {
print("\(key) ---> \(dict[key]!)") 感叹号:拆封还原
}
```Swift
第二种
for value in dict.value{
print(value)
}
```
```Swift
第三种
for (key, value) in dict.enumerate() {
print("\(index).\(value.0) --->\(value.1)")
} 
```

重要操作

  • 排序
    1.sort
    2.sortInPlace

说明:排序方法的参数是一个闭包(closure),该闭包的作用是比较数组中俩个元素的大小

let array = [23, 45 ,12 ,33, 56, 77]
array.sort(<) 比自然序,不用传参

array.sort({(one:Int,two:Int) -> Bool in return one < two
})
array.sort({(one,two) in one < two}) 省类型
array.sort({one,two in one < two})
array.sort({ $0 < $1})
array.sort{$0 < $1}
array.sort(<)
从复杂到简单的写法(排序)
数据调整三部:
  • 过滤
let array = [23, 45, 12, 89, 98]
// 筛选掉不满足条件的
let newArray = array.filter{ $0 > 50}
print(newArray) //[89, 98, 55]

  • 映射
let array = [23, 45, 12, 89, 98, 55]
//通过映射对数据进行变换
let newArray =  array.map{$0 % $10}
print(newArray)
  • 规约
let array = [23, 45, 12, 89, 98, 55]
let result = array.reduce(0,combine: +)
print(result)

函数和闭包

函数是独立的可重复使用的功能模块,如果程序中出现了大量的重复代码,通常都可以将这部分功能封装成一个独立的函数,在Swift中,函数是"一等公民",函数作为 类型来使用,也就是说函数可以赋值给一个变量或常量,可以将函数作为函数的参数或者返回值,还可以使用高阶函数。

func 函数名([参数1:类型,参数2:类型,...]) [throws|rethrows] -> 返回类型 {
函数的执行体 [return 表达式]
} 左花括号开始右花括号结束
  • 外部参数名
func addtion(a:Int, b:Int) -> Int {

}
  • inout参数
func mySwap<T>(inout a: T, inout _ b: T) {
  let temp = a
  a = b
  b = temp

  • 可变参数列表
func sum(input: Int...) -> Int {
  //...
}
  • 闭包:就是没有名字的函数(匿名函数)或者称之为函数表达式(Lambda表达式),Objective-C中与之对应的概念叫block.如果一个函数的参数类型是函数我们可以传入一个闭包表达式;如果一个函数的返回类型是函数我们可以返回一个闭包;如果一个类的某个属性是函数我们也可以将一个闭包表达式赋值给它。
{([参数列表])} [-> 返回类型] in 代码 }

面向对象编译(OOP)

基本概念

对象:接受消息的单元.对象是一个具体的概念.

类:对象是蓝图和模板,类是一个抽象概念.数据抽象和行为抽象
消息:对象之间通信的手段.通过给对象发消息可以让对象执行相应的操作,来解决问题

四大支柱

抽象:定义类的过程就是一个抽象的过程,需要做数据抽象和行为抽象.数据抽象找到对象属性(保存对象状态的存储属性),行为抽象找到对象的方法(可以给对象发的消息).

封装:
观点1.我们在类中写方法其实就是在封装API(接口),方法的内部实现可能会很复杂,但是这些对调用者来说是不可见的,调用只能看到方法有一个简单清晰的接口,这就是封装.
观点2.将对象的属性和操作这些属性的方法绑定在一起.
观点3.隐藏一切可以隐藏的实现细节,提供简单清晰的接口(界面)

继承:
从已有的类创建新的类 父类 -> 子类

多态:

1.子类在继承父类的过程中
2.用父类的对象去引用子类对象
3.重载 - overload
4.重写 - override

三个步骤

1.定义类

  • 数据抽象
    • 存储属性
  • 行为抽象
    • 方法 (写到类里面的函数就是方法)
      • 对象方法:给对象发的消息
      • 类方法: 给类发的消息,与对象的状态无关的方法,给类发消息(static.clase)
    • 计算属性
  • 构造器
    - 指派构造器
    - 便利构造器(convenience)
    - 必要构造器(required)
    2.创建对象
    3.给对象发消息

相关内容

  • 枚举

  • 结构(体)

总结: 类和结构的区别到底有哪些?什么时候应该使用结构?什么时候应该使用类?
答:

  • 扩展(extension)

  • 运算符重载

  • 下标运算(subscript)

  • 访问修饰符

    • private
    • internal
    • public

面向协议编程(POP)

协议

protocol 协议名[:父协议,...] {
    // 方法的集合(计算属性相当于就是方法)
}

1.协议表能力:
2.协议表约定:
3.协议表角色:

依赖倒转原则

设计模式

一个对象想做某件事情但自身没有能力做这件事情就可以使用委托回调,具体的步骤是:

  • 代理模式
  • 用协议实现委托回调:
  • 设计协议,被委托方要遵循协议并实现协议方法
  • 委托方有一个属性是协议类型,通过该属性可以调用协议中的方法
  • 委托方协议类型属性通常是可控类型,要写成 weak(弱)引用

注意:委托方的协议类型的属性通常是可空类型,所以要加weak弱引用

其他

  • 协议组合:protocol<协议1,协议2,协议3,....>
  • 可选方法
  • 协议扩展:对协议中的方法给出默认实现

泛型

让类型不在是程序中的硬代码(hard code)。

  • 泛型函数

  • 反省类/结构/枚举

相关知识

  • 泛型限定
  • where字句

错误处理

enum MyError: ErrorType{
  case A
  case B
  case C
}
  • throw
  • throws / rethrows
  • do // 包围出错的代码
  • catch // 捕获出错的代码
  • try // 尝试运行

边角知识

  • ARC
  • 正则表达式
  • 嵌套类型
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,290评论 4 363
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,399评论 1 294
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,021评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,034评论 0 207
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,412评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,651评论 1 219
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,902评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,605评论 0 199
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,339评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,586评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,076评论 1 261
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,400评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,060评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,083评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,851评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,685评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,595评论 2 270

推荐阅读更多精彩内容