1. 结构体struct 和 类class
(1) 结构体和类区别?
(2) 为什么使用结构体?
- 在多线程环境中,多个线程会共享堆上的内存,为了确保 线程安全,需要在堆上进行 加锁操作。
- 但是 堆上数据加锁操作 是很耗费性能的。
(3) 方法占用对象的内存么?
- 不占用
- 枚举、结构体、类 都可以定义方法
- 方法的本质就是 函数,放在代码段
2. 知识点
(1) 函数重载
- 函数名相同
- 函数个数不同 || 参数类型不同 || 参数标签不同
(2) 别名 typealias
(3) 输入输出参数 inout
- 在函数内部 修改 外部实参 的值
- 本质是 地址传递
(4) 可选项(可选类型)
-
类型名称
+?
,允许将值设置为nil
(5) 可选项绑定
- 判断 可选项 是否包含值
- 如果包含就自动解包,把值赋给一个临时的常量(
let
)或者变量(var
) ,并返回true
,否则返回false
(6) 可选项链
- 多个
?
可以链接在一起 - 如果链中任何一个节点是
nil
,那么整个链就会 调用失败
(7) 空合并 运算符 ??
- 使用 自动闭包
@autoclosure
技术
(8) 隐式解包
- 可选项 一旦被 设定值 之后,就会一直 拥有值
- 此时去掉检查,也不必解包
- 可以在类型后面加个 感叹号
!
定义一个隐式解包的可选项
(9) Any
、AnyObject
-
Any
:可以代表 任意类型(枚举、结构体、类,函数类型) -
Any0bject
:任意 类 类型
3. 闭包
(1) 闭包
- 一个函数 和 它所捕获的变量\常量环境 组合起来,称为闭包
- 一般指定义在 函数内部的函数
- 一般它捕获的是 外层函数的局部变量\常量
(2) 函数/闭包表达式
func sum(_ v1: Int, _ v2: Int) -> Int {
return v1 + v2
}
var fn = { (v1: Int, v2: Int) -> Int in
return v1 + v2
}
fn(10, 20)
(3) 尾随闭包
(4) 自动闭包 @autoclosure
4. 属性
(1) 属性
(2) 属性观察器
willSet
:会传递 新值newValue
didSet
: 会传递 旧值oldValue
-
调用时机:对象创建后的 第一次赋值时 开始调用
- 即初始化时(包含重载的
init
或重写的init
)不会调用。 - 初始化器 中设置属性值
- 属性定义 时设置初始值
- 即初始化时(包含重载的
(3) 单例
public class FileManage {
/// 只初始化一次
public static let shared = FileManage()
/// 初始化
private init() {}
func open() {
print("open")
}
}
FileManage.shared.open()
5. 属性方法、下标
(1) 方法
- 实例方法:通过 实例对象 调用
- 类型方法:通过 类型调用,用
static
或class
关键字定义
(2) mutating
- 结构体和枚举是 值类型
- 值类型的 属性 不能被自身的 实例方法 修改
- 在
func
关键字前加mutating
可以修改
(3) @discardableResult
- 在
func
前面加个@discardableResult
- 可以消除:函数调用后 返回值未被使用 的警告
(4) 下标
- 给任意类型(枚举、结构体、类) 增加下标功能
- 类似于 实例方法、计算属性,本质就是 方法(函数)
6. 继承
(1) 继承
- 只有类 支持继承
- 没有父类的类,称为:基类
- 子类可以重写父类的 下标、方法、属性,重写必须加上
override
关键字
-
被
class
修饰 的类型方法、下标,允许 被子类重写 -
被
static
修饰 的类型方法、下标,不允许 被子类重写
(2) 重写属性
- 子类可以将 父类的属性 重写为 计算属性
存储属性 - 子类重写后的 属性权限 不能小于 父类属性的权限
(3) final
- 被
final
修饰的 方法、下标、属性,禁止被重写 - 被
final
修饰的类,禁止被继承
7. 初始化器
(1) 初始化器
- 类、结构体、枚举都可以定义 初始化器
- 类有2种初始化器:
- 指定初始化器:调用 父类始化器;至少一个 指定始化器
- 便捷初始化器:调用 同类始化器;必须调用一个 指定初始化器
(2) Swift保证 初始化安全 流程
- 两段式初始化
- 初始化 所有存储属性
- 设置 新的存储属性值
-
安全检查
- 存储属性 全部 初始化完成
- 指定初始化器 必须先 调用父类始化器
- 便捷初始化器 必须先 调用同类始化器
- 完成之前,不调用任何实例方法、实例属性
(3) 重写
- 当重写父类的 指定初始化器 时,必须加上
override
- 当重写父类 便捷初始化器 的初始化器,不用加上
override
- 因为父类的 便捷初始化器 永远不会通过子类 直接调用
- 因此子类 无法重写 父类的 便捷初始化器
(4) 自动继承
- 子类 没有自定义 任何 指定初始化器
- 则自动继承 父类 所有的 指定初始化器
(5) required
-
required
修饰,子类部必须实现 该初始化器 (通过继承或者重写实现) - 子类重写了
required
初始化器,也必须加上required
,不用加override
(6) 可失败的初始化器 init?
(7) 反初始化器 deinit
- 类似于C++的析构函数、OC中的
dealloc
方法 - 父类的
deinit
能被 子类继承 - 子类的
deinit
执行完毕后,会调用父类的deinit
8. 高级运算符
(1) 溢出运算符
- Swift的算数运算符出现 溢出时 会抛出 运行时错误
- Swift有 溢出运算符(
&+、&-、 &*
),用来支持溢出运算**
(2) 运算符重载
- 类、结构体、枚举 自定义运算符 实现
(3) Equatable
- 判断实例 是否等价
- 遵守
Equatable
协议,重载==
运算符 - 等价于重载了
!=
运算符
(4) Comparable
- 判断实例 大小
- 遵守
Comparable
协议,重载相应的运算符
9. 高级运算符
(1) 扩展Extension
- Swift中的扩展,有点类似于OC中的 分类(
Category
) - 扩展可以为 枚举、结构体、类、协议 添加新功能
- 可以添加 方法、计算属性、下标、 (便捷)初始化器、嵌套类型、协议等等
扩展不能办到的事情:
- 不能覆盖 原有的功能
- 不能添加 存储属性,不能向已有的属性添加 属性观察器
- 不能添加 父类
- 不能添加 指定初始化器 或 反初始化器
- ...
(2) 访问控制
(3) 访问级别的使用准则
- 一个实体 不可以被 更低访问级别 的实体定义
(4) 元组类型
- 元组类型的访问级别是所有成员类型 最低的那个
(5) 泛型类型
- 在类型的访问级别、泛型类型参数的访问级别中
- 泛型类型的 访问级别最低
10. 内存管理
(1) ARC中3种引用
强引用(stong reference):默认强引用
-
弱引用(weak reference):
- 必须是可选类型的
var
,实例销毁后,ARC自动将 弱引用置为nil
- ARC自动给弱引用设置
nil
时,不会触发属性观察器
- 必须是可选类型的
-
无主引用(unowned reference):
- 不会产生强引用,实例销毁后 仍然存储 着实例的内存地址
- 实例销毁后访问无主引用,会产生 野指针
-
weak
、unowned
只能用在 类实例上面
(2) 循环引用
-
weak
、unowned
都能解决循环引用的问题 -
unowned
要比weak
少些 性能消耗 - 在生命周期中可能会 变为
nil
的使用weak
- 初始化赋值后再也 不会变为
nil
的使用unowned
(3) 逃逸闭包
- 非逃逸闭包、逃逸闭包,一般都是当做 参数 传递给函数
(4) 内存访问冲突
内存访问冲突会在两个访问满足下列条件时发生:
- 至少一个是 写入操作
- 它们访问的是 同一块内存
- 它们的访问 时间重叠(比如在同一个函数内)
如果下面的条件可以满足,就说明重叠访问结构体的属性是安全的:
- 只访问实例 存储属性,不是计算属性或者类属性
- 结构体是 局部变量 而非全局变量
- 结构体要么没有被闭包捕获要么 只被非逃逸闭包 捕获
11. 面向协议编程
(1) 种类
- 面向协议编程POP (Protocol Oriented Programming)
- 面向对象编程OOP (Object Oriented Programming)
(2) 三大特性:封装、继承、多态
- 多态:指允许 不同类的对象 对 同一消息 做出响应。(发送消息就是函数调用)
- 动态绑定:执行期间 判断所引用 对象的实际类型,调用其相应的方法。
- 作用:消除类型之间的 耦合关系。
(3) 抽取公共方法
protocol Runnable {
func run()
}
extension Runnable {
func run() {
print("run")
}
}
class BVC: UIViewController, Runnable {}
class CVC: UITableViewController, Runnable {}
(4) 高阶函数map、flatMap、filter、reduce
- map:对数组中的 每一个元素 做 一次处理
-
flatMap:
- 返回后的数组中 不存在nil,同时它会把 Optional解包
- (二维数组、N维数组)一同打开变成一个 新的数组
- filer:过滤,可以对数组中的元素按照 某种规则 进行一次过滤
- reduce:计算,可以对数组的元素进行 计算
(5) Swift支持KVO、KVC条件
- 属性所在的 类、监听器 最终继承自 NSObject
- 用 @objc dynamic 修饰对应的属性