Swift3到Swift4的一些坑
一、Substring
Swift 4 中有一个很大的变化就是String可以当做Collection来用,并不是因为String实现了Collection协议,而是String本身增加了很多Collection协议中的方法,使得String 在使用时看上去就是个Collection。
1 | let string = "IamBaylee" |
比如上面的样例,我们使用一些Collection协议的方法对字符串进行截取,只不过它们的返回结果不是String类型,而是 Swift4 新增的Substring类型。
为什么要引入Substring?
既然我们想要得到的就是字符串,那么直接返回String就好了,为什么要返回一个新增的Substring类型呢?答案是:性能。
- 当我们用一些Collection的方式得到String里的一部分时,创建的都是Substring。Substring 与原 String 是共享一个 Storage。这意味我们在操作这个部分的时候,是不需要频繁的去创建内存,从而使得 Swift 4 的 String 相关操作可以获取比较高的性能。
- 而当我们显式地将 Substring 转成 String 的时候,才会 Copy 一份 String 到新的内存空间来,这时新的 String 和之前的 String 就没有关系了。
使用Substring的注意事项
- 由于Substring与原String是共享存储空间的,只要我们使用了Substring,原 String 就会存在内存空间中。只有 Substring 被释放以后,整个 String 才会被释放。
- Substring 类型无法直接赋值给需要 String 类型的地方,我们必须用 String() 包一层。当然这时系统就会通过复制创建出一个新的字符串对象,之后原字符串就会被释放。
二、swap方法的变迁
Swift4之前我们可以用swap(_:_:)
来将两个变量的值进行交换
1 | var a = 1 |
Swift4之后,swap(_:_:)
方法被废弃,我们可以使用元组(tuple)来实现值交换:
1 | var a = 1 |
使用tuple方式的好处是,多个变量值也可以进行交换
1 | var a = 1 |
三、减少隐式@objc自动推断
Swift3中的使用方式
在项目中如果想把Swift的API暴露给Objective-C调用,需要增加@objc
。在Swift3中,编译器会在很多地方为我们隐式加上@objc
。比如当一个类继承于NSObject,那么这个类的所有方法都会被隐式地加上@objc
:
1 | class MyClass: NSObject { |
但这样做导致很多并不需要暴露给Objective-C的API也被加上了@objc
。而大量的@objc
会导致二进制文件的增加。
Swift4中的使用方式
在Swift4中隐式
@objc
自动推断只会发生在下面这种必须使用@objc
的情况:- 覆盖父类的Objective-C方法
- 符合一个Objective-C的协议
大多数地方必须显式地加上
@objc
1
2
3
4class MyClass: NSObject {
@objc func print(){} //显式地加上@objc
@objc func show(){} //显式地加上@objc
}如果在类前加上
@objcMembers
,那么它、它的子类、扩展里的方法都会隐式加上@objc
。1
2
3
4
5
6
7
8@objcMembers
class MyClass: NSObject {
func print(){} //包含隐式的@objc
func show(){} //包含隐式的@objc
}
extension MyClass {
fun makeName(){} //包含隐式的@objc
}如果在扩展前加上
@nonobjc
,那么该扩展的方法都不会隐式地加上@objc
。1
2
3
4
5
6
7
8@objcMembers
class MyClass: NSObject {
func print(){} //包含隐式的@objc
func show(){} //包含隐式的@objc
}
@nonobjc extension MyClass {
fun makeName(){} //不包含隐式的@objc
}