不管你是否主力 Swift, 这些事情你均可以了解一下

Swift 再等等?个人答案是:快上车 - 简书git

主力 Swift 或许真的要等一等 - 知乎专栏 程序员

上一周有两篇文章, 分别讨论了你们在现阶段到底该不应用 Swiftgithub

在这里我不是想给出一个答案该不应用 Swift, 只是想聊一聊我对于 Swift 的理解.objective-c

Swift 能不能取代 Objective-C?

那两篇文章都讨论了一个话题, Swift 到底能不能取代 Objective-C?编程

其实到如今为止 Swift 离替代 Objective-C 仍是很遥远,由于 Apple 内部一直在用 Objective-C 来作一些 Framework 的开发,低层也不可能用 Swift 实现swift

— Cyanapi

若是把取代定义为编写底层框架的话, 至少以 Swift 3 来讲, 毫无疑问是不可能的.数组

首先咱们先去探究一下为何苹果会选择 Objective-C 做为官方开发语言?

Objective-C 是在 C 的基础上加上一层面向对象, 在编写高性能模块的时候, 能够直接使用 C, 在编写对于性能不高的业务模块时, 就使用原生的 Objective-C.安全

目前苹果的框架, 底层实现都是使用 C , 而后再套上一层 Objective-C 去暴露外部接口. 这种方式既保证了性能, 又能保证 API 的易用性.app

并且苹果使用了大量的开源框架, 系统底层不少模块, 都已经有了开源的基于 C 语言的框架实现, 跟 C 的交互上, Swift 明显不如 Objective-C 那么方便.

除开语言生态, 还有一个问题是 Swift 的性能不如 C, Swift 在公布的时候, 就宣称运行效率能够媲美甚至超越 C. 但这是有前提的, 没有运行时损耗的状况下 Swift 才有可能与 C 的运行效率持平.

Swift 的运行时损耗到底来自哪里

Swift 的运行效率损耗主要来自于 ARC, 内存管理, 运行的时候, 一个对象会不停地进行 retain 和 release, runtime 必须一直 observe 每个对象的 retain count, 当 retain count 达到 0 的时候就释放这个对象. 而 C 就没有这个问题, 由于 C 没有对象, 没有运行时的损耗.

那解决方式也就很简单了, 换一种新的内存管理模式就好了(Swift 实际作法是直接引入了一种新模式, 与 ARC 并存).

目前主流的内存管理方式分三种:

  1. 手动: C 语言的 malloc 库, 特色就是无运行时损耗, 但很差控制释放内存的时机.
  2. 半自动: Objective-C 和 Swift 的 MRC/ARC, 有运行时损耗, 但基本上可让程序员不用去考虑内存管理的问题.
  3. 自动的: Java/Go 的 GC. 基本上同上, 但须要在某个时间点去中止全部线程, 释放内存的时机不可控.

Objective-C 的 MRC 还须要手动去写 retain/release, 在进化到 ARC 以后, 除了须要在类成员变量声明的时候, 显式地声明是 weak/strong/retain/copy 就能够了, retain/release 的插入交给编译器便可, ARC 其实已是实际上的自动化内存管理模式了.

而 Swift 在把指针抽象为引用类型, 加入 Mutable/Immutable 的概念以后, 就只须要偶尔写写 weak 就好了, 惟一须要对于内存管理费心的就是 retain cycle 的问题, 但也比以前省心不少了. 并且随着 Swift 工具链的发展, 这些问题均可以在编译期或者 Debug 时就暴露出来.

半自动的内存管理, 实际上还有一种, 就是 Rust 的 OwnerShip, 我我的的理解是, 这种方式实际上是 MRC/ARC 的一种延续, 但 MRC/ARC 内存释放的时机仍是须要在运行时才能知道, 而 Rust 能够在编译期就解析出何时能够释放掉内存, 从而省略掉 retain/release 的存在, 也不必专门跑一个 runtime 去监测对象的引用计数., 从而达到比 ARC 更高的运行效率

仔细思考一下这种自动化的内存管理模式, 其实都是在把指针分类, 加上 context(上下文), 抽象出来, 暴露给编译器更多与关于指针的信息, 而不是单纯的一个内存地址, 从而让编译器能够分析释放对象的时机.

Rust 也不例外, 既然要达到比 ARC 更高的运行效率, 那就必然要提供给编译器更多的指针信息, 所以在指针声明和传递时都须要显式地声明全部权, 代码量也会相应地增多, 对于程序员的要求也会更高.

虽然写起来比 ARC 更麻烦一点, 但也比 C 那种原始的方式简单不少, 提供给了 Rust, Swift 这些”现代编程语言”编写底层程序的可能性.

补充: 学术界对于 GC 的研究已经不少了, 但关于 ARC 的研究仍是不多, ARC 还有很大的进步空间. 甚至说若是能够在编译期就检测到对象实际释放的时机的话, 就能够直接省略掉中间的那些 retain/release, 没必要在运行时再去检测是否应该释放掉这一段内存.

Swift 何时会引入这种内存管理模式

在我写这篇文章的时候, Swift 团队正式发布了引入 OwnerShip 的提案(正式方案?), 喵神大大也翻译了这篇文章, 更多技术细则能够去看喵神大大的翻译.

一句话总结: Swift 的团队但愿 Swift 可以进化成为一门系统编程语言, 因此才不惜牺牲 ABI 稳定性去加入这个 Feature.

Swift 是为了取代 Objective-C 而生的吗

在 Cyan 大大的那篇文章下面, 有这么一条回复.

LLVM 之父, Swift 的做者之一 Chris Lattner 在 ATP 的一期访谈里聊过这件事情, 直接贴原话:

There's a ton of stuff to love about Objective-C, and while there are a few things that are ugly about it, some “@“ signs and semicolons and other stuff like that, we can make Objective-C better. The question was always: Why not just make Objective-C better? Why don't we just keep evolving Objective-C? Why do we want to face potential disruption in terms of moving the entire development community to something [23:00] new?

We kicked that around for a long time. We talked about both sides and we came to realize that, yes, we can and should make Objective-C better, and we continued to invest in Objective-C. We did things like ARC, for example, which is a major effort, but…

We were talking about, okay, can we just make Objective-C better and can we feature-creep it to the language we want for the fullness of time? Because if we can, that would be much less disruptive to the community. We decided that, yeah, we can move Objective-C a lot closer to what we want so we can get automatic memory management with ARC, for example, but we can't ever take away the problems that lead to Objective-C being unsafe. The fundamental problem was Objective-C was built on top of C. [24:00] C inherently has pointers. It has uninitialized variables. It has array overflows. It has all these problems that even if you have full control of your compiler and tool stack, you just can't fix. To fix dangling pointers, you would have to fix lifetime issues, and C doesn't have a framework to reason about that, and retrofitting that into a compatible way into the system just wouldn't really work.

If you took away C from Objective-C, you couldn't use C arrays on the stack, for example. And if you [24:30] couldn't do that, there's entire classes of applications where the performance just wouldn't be acceptable. We went around, around, around. We said the only way that this can make sense in terms of the cost of the disruption to the community is if we make it a safe programming language: not “safe” as in “you can have no bugs,” but “safe” in terms of memory safety while also providing high performance and moving the programming model forward. That was really kind [25:00] of the ideas that came together to make Swift being worth the investment and being worth being disruptive to the community. A lot of these kinds of pitches and ideas were being held in very small, small, small meetings. Coming out of WWDC 2013 is when we and the executive team decided okay, let's really commit to this, and that’s when the developer-tools [25:30] team came to know about it and really started working hard on it.

— 节选自 Accidental Tech Podcast: Chris Lattner interview

内容有点长, 你们能够看一下我高亮的部分, 实际上苹果的团队也很犹豫, 到底要继续优化 Objective-C, 仍是应该发明一门新的语言. 最后两种方式都尝试一下, 而后 Objective-C 就有了 ARC, 点语法等等新功能.

但最后, 苹果的团队发现 Objective-C 这门语言不安全最关键的缘由仍是由于它是基于 C 语言的, 它有指针, 它有不彻底初始化的变量, 它会数组越界. 即便苹果的团队对于工具链和编译器有完整的控制权, 也没办法很好地解决这个问题.

苹果的团队想了又想, 反复思虑以后, 仍是决定打断整个开发社区, 去建立一门 Safe 的编程语言, 不仅是那种没有 bug的 Safe, 而是保持安全的同时还能提供高性能的, 推进整个编程范式前进的那种 Safe.

Swift 与 Objective-C 并不是是对立的, “Objective-C is Great”, Swift 只是苹果提供的一个 “better option”.

ABI Stability vs. API Stability

关因而否应该主力 Swift 另外一个关键的争论点在于, ABI 不稳定.

由于 Swift 的 ABI 不稳定而放弃 Swift 的人好像特别多. 但是我看到的不少文章都没有提到到底 ABI 稳定对于咱们应用开发者表明着什么? ABI 与 API 又有什么区别?

ABI (Application Binary Interface)

在计算机中,应用二进制接口(英语:application binary interface,縮寫為 ABI)描述了应用程序(或者其余类型)和操做系统之间或其余应用程序的低级接口。

… ABI不一样于应用程序接口(API),API定义了源代码和库之间的接口,所以一样的代码能够在支持这个API的任何系统中编译,然而ABI容许编译好的目标代码在使用兼容ABI的系统中无需改动就能运行。

zh.wikipedia.org/wiki/应用二进制接…

ABI 主要是描述程序跟操做系统之间的低级接口, 说白了就是Swift 二进制程序与系统或者其它程序交互时会调用的接口, 通常这部分都是由编译器去处理, 除非咱们进行很底层的开发, 或者是想要 hack 编译过程(例如把 Swift 编译到 JavaScript) 才会须要去考虑这方面的东西.

ABI 的不稳定会形成如下结果:

  1. 打包 Swift 程序时, 必须嵌入一个 Swift 标准库.咱们每次打包应用时, 都须要嵌入一个 Swift 的标准库, 由于系统不知道咱们使用程序时用的 ABI 是哪一个版本, 因此必须没办法在系统内部内置一套标准库. 用过 pyenv, rvm 或者 nvm 的人就大概知道这里的过程.
  2. 第三方 SDK 开发困难. 你的应用与第三方 SDK 使用的 ABI 版本若是不一样就会出现问题, 例如说 Swift 2和 Swift 3打包出来的库就没办法互相调用. 非要支持的话, Swift 每出一个版本就须要跟着打包一个 SDK, 并且以前的 SDK 没办法向后兼容.

ABI 的稳定到底意味着什么

说明完了 ABI 是什么, 以及 ABI 不稳定会形成什么.

那 ABI 稳定对咱们有什么实际意义? Chirs 在 ATP 里讨论过这个问题, 继续贴原话:

Another part of it is that ABI stability is super-important, but it's not as important as people think it is for application developers. It's really important to Apple, [51:30] but what we realized in the Swift 3 timeframe is that the thing app developers would benefit from the most was actually source stability. Who actually wants their application to be broken when they get a new version of Xcode? Really nobody, right?

ABI 稳定超级重要, 不过对于应用开发者来讲, 并无你们想象的那么重要. 可是对于苹果来讲很重要. 咱们相信在 Swift 3 以后, 应用开发者受益最多的仍是代码稳定(API Stability), 谁愿意升级了一下 Xcode 就运行不了本身的程序呢?

ABI 的稳定对咱们来讲真的没有那么重要, 大厂开发 SDK 也只要选择 Objective-C 就好了(因此不能用 Swift 才是痛苦的地方?). 再给点力的话, 底层使用 Objective-C 实现, 用 Swift 负责暴露外部接口也行(例如 Instagram 开源的 IGListKit), Swift 版本迁移的工做就会大幅减小了. ABI 不稳定最痛苦的实际上是苹果的底层开发人员, 他们必须实时去更新框架对外的接口, 想办法让官方框架去兼容不一样版本的 Swift.

补充: 写这篇文章的时候, 柏学网翻译了 Swift 官方关于 ABI 稳定的声明, 你们能够去看看

API 稳定还会是问题吗

Halfway through the release, we pivoted and source stability became the goal, so I'm really excited that when Swift 3.1 or Swift 4 comes out that it's still going to be able to build [52:00] Swift 3 code, and even if there are minor changes that need to be made for one reason or another, that you can upgrade and you have great compatibility with your old code and you don't have to start the migrator before you can do anything. So it's going to be a great improvement for people's lives.

Swift 4的开发途中, 咱们定下了一个目标, 不管是在 Swift 3.1 仍是 Swift 4 里, 都必须能够编译 Swift 3的代码(编译器提供相应的编译模式)

API 不稳定致使的代码迁移, 可能 Swift 1 到 Swift 2 对于你们的冲击太大, 因此你们才会有那么深的怨念, 我没有经历过那一段日子没有发言权.

但 Swift 2 到 Swift 3 的迁移我是经历过的, 公司项目刚起步, 一万多行代码左右, 自动转换加上一个晚上我就让程序成功跑起来了, 随后一个星期修修 bug, 适配一下新的 Feature 也就彻底过分过去了, 后来陆陆续续看了 Enjoy, Airbnb 等等关于 Swift 迁移过程的讲述, 过程其实也没有很痛苦. 但 CoreGraphic 等框架的 Swift 化带来的麻烦可能会更多一点, 代码耦合度过高的项目可能会在这里陷得很深.

Swift 3 以后会好不少, Swift 4的编译器提供了 Swift 3的编译模式, 至少咱们能够慢慢地去迁移咱们的代码, 而不是一升级 Xcode 就连程序也跑不起来.

API 以后确定还会改的, 但其实从 Swift 2 到 Swift 3 的过程里, 我以为不少原则性的东西其实已经稳定下来的, 接下来的改动要么就是很小, 要么就是特别有规律性, 迁移的时候花点时间去看看第三方发的迁移指南, 就能够很平稳地迁移过去了.

一句话总结: ABI 不稳定对于咱们应用开发者的影响并无那么大, API 以后虽然会变, 但以后确定会给你充足的迁移时间

Swift 之我见

说了这么多, 但愿你们如今能够理解 Swift 的团队究竟是基于什么样的缘由, 才作出了各类决策, 才演变出了如今的 Swift.

最后, 我想聊聊本身对于 Swift 的看法.

Swift 目前的问题

代码稳定, 其实都是小事情, 迁移, 几十万行代码, 分配给全部人, 最多也就是一个星期的事情. Swift 的开发者都很积极, 主流的第三方框架基本上两个星期内都能更新到最新的版本, 我用的库 75% 都从 beta 时期就开始跟进 Swift 的更新.

Swift 3 最大的问题我以为仍是工具链不稳定

  • 增量编译作的很差. 编译随时 Segment Fault, 必须 clean 一次才行.

  • 超长的编译时间. 每次编译出错, clean 以后可能须要编译七八分钟, 以前我记得还有人总结了一份什么样的语法会致使编译时间变长的列表, 为了编译时间缩短而却强行改变代码应有的样子, 我以为很不值得.
    我采用的解决方式就是把底层模块抽出来, 独立成一个框架, 使用 Carthage 去进行包管理, 所有编译成静态库, debug 编译的时候, 只要连接上去就好了, 大大减小编译时间. (顺带一说, Carthage 是用 Swift 写的)

  • 代码高亮随时崩, 代码补齐几乎没有. Xcode 很容易变白板, 我我的而言发生状况很少, 一天能赶上个两三次左右, 可是代码补齐就真心是彻底没有, 天天基本上都是盲打, 只有像是 UICollectionElementKindSectionFooter 这种才会等等代码补齐. (补充一下, AppCode EAP 对于 Swift 3的支持异常的好, 补齐跟高亮都可以很好地知足平常需求, 个人 Air 8g 内存就能跑的很好)

这两个问题虽然很小很不起眼, 但对我平常工做影响是最大的.

以前 Chris Lattner 离开苹果加入特斯拉的消息你们应该都知道, 但 Chris 依旧保留本身在 Swift 开发小组的位置, 而实际上 Chris 在苹果也只有很小一部分时间分配给 Swift(LLVM 对于这个世界影响更大一点), 接任的 Ted, 实际上也是以前实际上的 Swift 开发小组组长, 他以前也是 Rust 的主要开发者之一, 初版的 Clang 静态分析器也是 Ted 一我的撸出来的.

Chris 平时主要负责提一些”天马行空”的想法, 打乱掉开发小组的计划, Ted 负责把这些想法落地.

Ted 我的更倾向于优化编译, 提升开发体验, 比起 ABI 稳定优先级更高, 但具体决策仍是得根据具体状况去决定.

虽然开发体验对我来讲也很重要, 很难割舍, 但我隐约感受不管是外部, 仍是苹果内部, 留给 Swift 开发团队的时间可能不会特别多了, 加紧开发功能性的东西, 赶快稳定 ABI 可能会更加剧要.(只是我的感受, 单纯的我的感受)

Swift 目前的热度主要仍是由于 iOS 平台的强势, 继续增强什么语法糖, 优化开发体验, 最终也只会把 Swift 坑进 iOS 里, 只有让 Swift 变得更强大, 可以在更多领域有所发挥, 才能反哺 Swift, 让 Swift 变成一门伟大的语言.

Swift 很 Apple

Swift 吸取了不少语言的特色, 以致于各类不一样语言的开发者写 Swift 的时候都会以为特别熟悉特别亲切. Chris 说 Swift 并非想成为某一门语言的增强版, 也不是在模仿哪一门语言, Swift 只是想作到最好, 而想要作到最好就必须去吸取现有语言的优势, 经过某种方式去把它们糅合到一块儿. 相似的一句话, 乔布斯也说过, “咱们不是刻意在模仿谁, 只是想作到最好, 若是作到最好须要学习别人的一些地方, 那就学习呗”, 这些都只是过程罢了, Best 才是结果.

Swift 的 ABI 不稳定, 影响最大的实际上是苹果本身, 但由于 Swift 想成为更好的语言, 因此一再拖延. 延期, 回炉再造, 而后再拿出一个最好的”做品”, 就像苹果的其它做品.

Swift 还很不成熟, 各类意义上都不成熟, 须要作的事情不少, 泛型系统, 内存管理模型, 性能, 异步模型, POP 的探索, 编译的优化, ARC 的优化, 函数派发机制, 字符串处理, 更好的异常处理……

结语

Swift 对我来讲是一种浪漫, 一种对于苹果文化的崇尚.

推荐阅读: