语言的基础部分
程序是指令的集合,写程序就是写一系列的指令去控制计算机去做我们想做的事情。
编译:将程序设计语言转换成计算机能够理解的机器语言或者某种中间代码的过程。
冯诺依曼体系结构的计算机:
- 使用二进制
- 程序存储执行
变量和常量
定义变量和常量是为了保存数据,变量和常量就是某种类型的值得存储空间。
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.见名知意
- 命名私有的属性和方法时以下划线开头
运算符:Swift中的运算符其实都是函数
- 赋值运算符:=、+、-=、...
- 算术运算符:+、-、*、/、%
- 关系(比较)运算符:==、!=、<、<=、>、>=
- 逻辑运算符:&&、||、!
- 三元条件运算符:? :
- 其他运算符:[]、.、??、?、!、
字面(常)量:
- 整数字面量: 10、1_234_567、0x10、0o10=8、0b10=2
- 小数字面量: 123.45、1.2345e2=1.2345x10⑃2、0xab.cdp2
- 字符字面量: "e"、"\n"、"\u(41)"、"\u(e9)"
- 字符串字面量: "Hello"、"caf\u(e9)"
- 布尔字面量: true、false
- 空值字面量: nil
- 类型字面量: 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 = []
var array2 = [1, 2, 3, 4, 5]
var array3 = [Int](coount: 5, repeatedValue: 0)
var array3 = Array(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..
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..
for(index, array) in scoresArray.enumerate(){
var sum = 0.0
for score in array {
sum += score
}
print("\(namesArray[index]的平均成绩为:\(avg)")
}
for i in 0..
数组是使用联系的内存空间来保存
集合
集合在内存中是离散的,集合中的元素通过计算Hash Code(哈希码或散列码)来决定存放在内存中的什么位置,集合中不允许有重复元素
- 创建集合
集合的遍历
var set: Set = [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(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
- 正则表达式
- 嵌套类型