Swift4.0 新特性----Xcode9的优化

New Build System


Xcode 9 引入了 New Build System,可在 Xcode 9 的 File -> Project Settings... 中选择开启。



预编译 Bridging Headers 文件


对于 Swift 和 Objective-C 混合的项目,Swift 调用 Objective-C 时,需要建立一个 Bridging Headers 文件,然后把 Swift 要调用的 Objective-C 类的头文件都写在里面,编译器会读取 Bridging Headers 中的头文件,然后生成一个庞大的 Swift 文件文件内容是这些头文件内的 API 的 Swift 版本。然后编译器会在编译每一个 Swift 文件时,都要编译一遍这个庞大的 Swift 文件内容

有了预编译 Bridging Headers 以后,编译器会在预编译阶段把 Bridging Headers 编译一次,然后插入到每个 Swift 文件中,这样就大大提高了编译速度。

苹果宣称 Xcode 9 和 Swift 4 对于 Swift 和 Objective-C 混合编译的速度提高了 40%。


Indexing 可以在编译的同时进行


用 Swift 开发项目时,近几个版本的 Xcode 进行 Indexing 的速度慢的令人发指。Xcode 9 和 Swift 4 在这方面做了优化,可以在编译的同时进行 Indexing,一般编译结束后 Indexing 也会同时完成。


COW Existential Containers


Swift 中有个东西叫 Existential Containers,它用来保存未知类型的值,它的内部是一个 Inline value buffer,如果 Inline value buffer 中的值占用空间很大时,这个值会被分配在堆上,然而在堆上分配内存是一个性能比较慢的操作。

Swift 4 中为了优化性能引入了 COW Existential Containers,这里的 COW 就代表 “copy-On-Write”,当存在多个相同的值时,他们会共用 buffer 上的空间,直到某个值被修改时,这个被修改的值才会被拷贝一份并分配内存空间。



移除未调用的协议实现


看下面的例子,Date 实现了 Equatable 和 Comparable 协议。编译时如果编译器发现没有任何地方调用了对 Date 进行大小比较的方法,编译器会移除 Comparable 协议的实现,来达到减小包大小的目的。
struct Date {
    private let secondsSinceReferenceDate: Double
}
extension Date: Equatable {
    static func ==(lhs: Date,rhs: Date) -> Bool {
        return lhs.secondsSinceReferenceDate == rhs.secondsSinceReferenceDate
    }
}
extension Date: Comparable {
    static func <(lhs: Date,rhs: Date) -> Bool {
        return lhs.secondsSinceReferenceDate < rhs.secondsSinceReferenceDate
    }
}


减少隐式 @objc 自动推断


在项目中想把 Swift 写的 API 暴露给 Objective-C 调用,需要增加 @objc。在 Swift 3 中,编译器会在很多地方为我们隐式的加上 @objc,例如当一个类继承于 NSObject,那么这个类的所有方法都会被隐式的加上 @objc。
class MyClass: NSObject {
    func print() { ... } // 包含隐式的 @objc
    func show() { ... } // 包含隐式的 @objc
}

这样很多并不需要暴露给 Objective-C 也被加上了 @objc。大量 @objc 会导致二进制文件大小的增加

在 Swift 4 中,隐式 @objc 自动推断只会发生在很少的当必须要使用 @objc 的情况,比如:

复写父类的 Objective-C 方法
符合一个 Objective-C 的协议
其它大多数地方必须手工显示加上 @objc。

减少了隐式 @objc 自动推断后,Apple Music app 的包大小减少了 5.7%。



Exclusive Access to Memory


在遍历一个 Collection 的时候可以去修改一个元素的值,但是在遍历时如果去添加删除一个元素就可能会引起 Crash。
例如为 MutableCollection 扩展一个 modifyEach 方法修改每个元素的值,代码如下:

extension MutableCollection {
    mutating func modifyEach(_ body: (inout Element) -> ()) {
        for index in self.indices {
            body(&self[index])
        }
    }
}

假如在调用 modifyEach 时去删除元素:
var numbers = [1,2,3]
numbers.modifyEach { element in
    element *= 2
    numbers.removeAll()
}

就会在运行时 Crash。
Swift 4 中引入了 Exclusive Access to Memory,使得这个错误可以在编译时被检查出来。


兼容性


Xcode 9 中同时集成了 Swift 3.2 和 Swift 4。 Swift 3.2 完全兼容 Swift 3.1,并会在过时的语法或函数上报告警告。 Swift 3.2 具有 Swift 4 的一些写法,但是性能不如 Swift 4。 Swift 3.2 和 Swift 4 可以混合编译,可以指定一部分模块用 Swift 3.2 编译,一部分用 Swift 4 编译。 迁移到 Swift 4 后能获得 Swift 4 所有的新特性,并且性能比 Swift 3.2 好。 总结:当 Xcode 正式版发布后,现有的 Swift 代码可以直接升级到 Swift 3.2 而不用做任何改动,后续可以再迁移到 Swift 4。或者直接迁移到 Swift 4 也可以,Swift 4 相比 Swift 3 的 API 变化还是不大的,很多第三方库都可以直接用 Swift 4 编译。Swift 1 到 2 和 Swift 2 到 3 的迁移的痛苦在 3 到 4 的迁移上已经大大改善了。

相关文章

软件简介:蓝湖辅助工具,减少移动端开发中控件属性的复制和粘...
现实生活中,我们听到的声音都是时间连续的,我们称为这种信...
前言最近在B站上看到一个漂亮的仙女姐姐跳舞视频,循环看了亿...
【Android App】实战项目之仿抖音的短视频分享App(附源码和...
前言这一篇博客应该是我花时间最多的一次了,从2022年1月底至...
因为我既对接过session、cookie,也对接过JWT,今年因为工作...