重读 Swift (5.0) 第四篇
Type Casting
is可用于所有的类型,包括protocol,判断是否是某个类型,class的子类, 遵守了某个协议as用于类型转换,可用于所有类型,返回可选型的转换后的类型
Protocols
protocol可以通过在protocol前加objc并且在方法和属性前加@objc optional关键子定义可选的方法和属性- 该
protocol只能用于继承于Objective-C的class类型中或者同样被@objc修饰的类中 - 可选的方法和属性在调用时都会是
optional类型,可能需要解包
- 该
protocol可以继承多个其它的protocolprotocol的extension中可以新增方法,可以被遵守protocol的实例调用- 对于
protocol加约束的扩展,如果一个实例满足多个约束,则遵守最严格最具体的约束
Generics
-
范型的目的是实现灵活/可重用的函数和类型
-
对一个范型类型添加
extension的时候,不用在extension中指定范型类型名,可以直接用原类型中定义好的范型类型名 -
protocol中可以使用associatedtype实现范型protocol SomeProtocol { associatedtype Item: Equatable // 可以添加约束 } struct SomeStruct: SomeProtocol { typealias Item = Int // 如果满足类型推断,可以省略。swift可以通过使用了Item的协议条件的实现中推断出Item的类型 } -
可以通过
where对多个范型类型进行限定,多个where条件之间用逗号分隔func allItemsMatch<C1: Container, C2: Container> (_ someContainer: C1, _ anotherContainer: C2) -> Bool where C1.Item == C2.Item, C1.Item: Equatable { // Check that both containers contain the same number of items. if someContainer.count != anotherContainer.count { return false } // Check each pair of items to see if they're equivalent. for i in 0..<someContainer.count { if someContainer[i] != anotherContainer[i] { return false } } // All items match, so return true. return true }
Automatic Reference Counting
-
当
ARC将一个weak指针置为nil时,属性observers不会被调用 -
使用捕获列表解决
closure的循环引用问题,列表的多个捕获对使用逗号分隔lazy var someClosure: (Int, String) -> String = { [unowned self, weak delegate = self.delegate!] (index: Int, stringToProcess: String) -> String in // closure body goes here }
Memory Safety
-
对内存的访问分为即时的(
instantaneous)和长期的(long-term)long-term的操作是指在一次操作开始后结束前可能会发生其它的操作
-
发生内存安全的问题的条件是
- 至少有一个写操作
- 操作的是同一块内存
- 和写操作的时间重叠
-
In-Out参数导致的内存安全问题-
所有的非
In-Out参数被评估后,所有的In-Out参数的写权限开始,直到函数的结束var stepSize = 1 func increment(_ number: inout Int) { number += stepSize } increment(&stepSize) // increment中对stepSize的读写重叠,造成内存冲突 -
对于值类型的属性的修改实际是对整个值的修改,所以也有可能造成内存冲突
var playerInformation = (health: 10, energy: 20) balance(&playerInformation.health, &playerInformation.energy) // Error: conflicting access to properties of playerInformation” -
同时满足以下条件不会发生内存安全问题
-
只操作了实例的存储属性,没有操作计算属性和类属性
-
结构体是一个局部变量,非全局变量
func someFunction() { var oscar = Player(name: "Oscar", health: 10, energy: 10) balance(&oscar.health, &oscar.energy) // OK } -
结构体没有被任何闭包捕获或者只被非逃逸闭包捕获
-
-
Access Control
-
默认的权限控制是
internal -
自定义类型
- 标记为
private或者fileprivate,它的成员默认也是对应的权限控制 - 标记为
public,它的成员默认是internal,包括默认初始化方法 - 结构的默认的按成员初始化方法的权限为成员中最小的
- 标记为
-
元组类型的权限控制取成员中小的
-
方法的权限默认取参数和返回值类型中最小的,如果默认计算出的权限和上下文中默认的不一致,需要显式标记
-
枚举类型的
case的权限适合枚举的定义一致的 -
嵌入类型
- 被嵌入到
private或者fileprivate中时,默认取对应的权限 - 被嵌入到
public或者internal中时,默认取internal,如果要扩大需要显式标记
- 被嵌入到
-
子类不能将父类重写为更高权限的,可以将成员重写为比父类更高的权限
-
协议类型的成员和协议的权限相同
-
extension默认情况下,
public和internal的extension为internal,private和fileprivate的extension为对应权限 -
typealias的权限小于等于被alias的对象
留下评论