Skip to content

Latest commit

 

History

History
72 lines (37 loc) · 5.64 KB

是否应该选择swift.md

File metadata and controls

72 lines (37 loc) · 5.64 KB

是否应该选择swift

Swift 能不能取代 Objective-C?

其实到现在为止 Swift 离替代 Objective-C 还是很遥远,因为 Apple 内部一直在用 Objective-C 来做一些 Framework 的开发,低层也不可能用 Swift 实现

首先我们先去探究一下为什么苹果会选择 Objective-C 作为官方开发语言?

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

而且苹果使用了大量的开源框架, 系统底层很多模块, 都已经有了开源的基于 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 并存).

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

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

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

一句话总结: Swift 的团队希望 Swift 能够进化成为一门系统编程语言, 所以才不惜牺牲 ABI 稳定性去加入这个 Feature.

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

实际上苹果的团队也很犹豫, 到底要继续优化 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 不稳定。

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

程序接口(API),定义了源代码和库之间的接口。

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

ABI 的不稳定会造成以下结果:

  • **打包 Swift 程序时, 必须嵌入一个 Swift 标准库。**我们每次打包应用时, 都需要嵌入一个 Swift 的标准库, 因为系统不知道我们使用程序时用的 ABI 是哪个版本, 所以必须没办法在系统内部内置一套标准库.
  • **第三方 SDK 开发困难。**你的应用与第三方 SDK 使用的 ABI 版本如果不同就会出现问题。

ABI 不稳定最痛苦的其实是苹果的底层开发人员, 他们必须实时去更新框架对外的接口, 想办法让官方框架去兼容不同版本的 Swift.

API 稳定还会是问题吗

Swift 4的开发途中, 我们定下了一个目标, 无论是在 Swift 3.1 还是 Swift 4 里, 都必须可以编译 Swift 3的代码(编译器提供相应的编译模式)。

ABI 不稳定对于我们应用开发者的影响并没有那么大, API 之后虽然会变, 但之后肯定会给你充足的迁移时间。

Swift 目前的问题

  • 增量编译做的不好. 编译随时 Segment Fault, 必须 clean 一次才行.
  • 超长的编译时间. 每次编译出错, clean 之后可能需要编译七八分钟。解决方式就是把底层模块抽出来, 独立成一个框架, 使用 Carthage 去进行包管理, 全部编译成静态库, debug 编译的时候, 只要链接上去就行了, 大大减少编译时间, 而且由于判断增量编译的工作量减少了, 索引速度也会大大提高, 代码补齐跟代码高亮会工作地更好一点. (顺带一说, Carthage 是用 Swift 写的)
  • 代码高亮随时崩, 代码补齐几乎没有.