学习 Swift 编程:准备好迎接黄金时段了吗?

已发表: 2022-03-11

Apple 在今年 6 月推出了 Swift,一种用于编写 iOS 应用程序的新编程语言,在整个 iOS 开发者社区中引起了极大的轰动和兴奋。

自发布以来,许多 iOS 开发人员一直在努力解决是否、如何以及何时从 Objective-C 过渡到 Swift 的问题。 对于每个团队和每个项目,这个问题的答案当然会有所不同。

您可以阅读大量文章,涵盖 Swift 的许多优点。 因此,在本文中,我们将重点关注在学习使用 Swift 开发应用程序之前可能需要考虑的一些问题,而不是重复这些相同的观点。

使用 Swift 编程可能会或可能不会准备好迎接黄金时段 - 你学习 Swift 语言了吗?

但首先,让我们把时钟拨回去一点……

在 Swift 之前:你会使用 Objective-C,而且你会喜欢它……

那一年是 2010 年,iPhone 还不到 3 年,为 iPhone 编写原生应用程序的能力才出现了大约 2 年。 当年 4 月 8 日,Apple 发布了 iPhone OS 版本。 iPhone OS(在它更名为 iOS 之前)包括了多任务处理、快速应用程序切换和后台服务等诱人的新功能。 可以理解的是,iPhone 开发人员渴望获得新的 SDK 并开始使用所有这些令人兴奋的新功能。

但 iPhone OS 4 SDK 包含一个意想不到的重磅炸弹。 这个重磅炸弹不在软件中,而是在使用协议中。 对于 iPhone OS 4 SDK,开发者协议的第 3.3.1 节已更新,包含以下令人不安的语言:

应用程序必须最初是用 Objective-C、C、C++ 编写的……并且只有用 C、C++ 和 Objective-C 编写的代码才能编译并直接链接到文档化 API。
– iPhone OS 4 SDK 开发者协议第 3.3.1 节

不用说,这个新的限制令许多开发者感到意外。 由史蒂夫乔布斯本人提供的官方更改原因是为了防止使用跨平台工具,例如最近发布的 Flash CS5。 引用乔布斯的话说,“平台和开发人员之间的中间层最终会产生 [原文如此] 不合标准的应用程序”。 但是,Apple 打击这些“中间层”的方法是限制可用于编写 iPhone 应用程序的编程语言,这一事实更多地揭示了 Apple 的想法:Objective-C 应该对任何人都足够好。

同意这一说法是可以原谅的,因为 Objective-C 连续两年获得 Tiobe Index 的“年度编程语言”奖。 但现实情况是,Objective-C 的流行是不断增长的应用生态系统的一个功能,而不是相反。 早在 2010 年,很多人就已经对 Objective-C 不满意,因此,用其他编程语言编写 iPhone 应用程序的替代方法已经出现。

最终,在整个开发者社区的压力下,仅仅五个月后,Apple 就撤销了对 SDK 开发者协议第 3.3.1 节的这些更改。 不过,信息很明确:如果您想为 iPhone 编写应用程序,您可能应该使用 Objective-C。

… 或者可能不是。 输入新的 iOS 语言 Swift。

从那次事件到 2014 年 6 月苹果公司向开发人员介绍其新语言 Swift 时快进了 4 年。 如果说 4 年前的信息是苹果对 Objective-C 非常满意,那么 Swift 的介绍所传递的信息就是苹果终于准备好承认真相了。 Objective-C 可能不一定是编写移动应用程序的最佳语言。

关于 Swift 如何是一种比 Objective-C 更“现代”的语言,已经有很多说法了。 如果您对如何学习 Swift 编程语言感兴趣,您可能需要查看从 Objective-C 迁移到 Swift 的指南。

不过,您应该注意到的是,Objective-C 和 Swift 语言之间有两个重要的区别:

  1. Swift不是C 语言的严格超集。
  2. Swift 是静态类型的,而不是动态类型的。

不是 C 的严格超集意味着 Swift 可以自由地使用原本不允许的语法结构。 例如,这使得在 Swift 中实现自定义运算符成为可能。

静态类型意味着 Swift 可以利用 Haskell 等语言开创的类型系统的许多最新进展。

尽管在公开之前已经开发了 4 年,但 Swift 仍然是一门年轻的编程语言,因此它有许多警告。

与 Objective-C 的兼容性

iOS 与 OS X 有着共同的遗产,而 OS X 的历史则源于 1989 年首次发布的 NeXTSTEP 操作系统。NeXTSTEP 最初主要是用 Objective-C 编写的,OS X 和 iOS 中的许多核心库都可以追溯到它们的根源回到这些原始实现的方法。 (顺便说一句,这就是核心类(如NSString )上无处不在的“NS”前缀的来源。)虽然理论上 Swift 可以在没有这些核心库的情况下存在,但现实情况是,您可能在不久的将来编写任何 Swift 程序必须与Objective-C接口。

值得称赞的是,Swift 背后的开发人员做得非常出色,使与现有 Objective-C 库的交互尽可能轻松。 这并不是说这个过程完全没有痛苦。 Apple 提供了一个有用的指南,解释如何从 Swift 调用 Objective-C 代码,反之亦然,但有一些重要的阻抗不匹配需要注意。

也许最明显的不匹配与头文件有关。 Objective-C,由于它的 C 根源,仍然要求函数在被调用之前被声明。 调用库时,这些声明将在库的头文件中找到。 然而,Swift 不使用头文件。 所以,如果你想从 Objective-C 调用 Swift 代码,你首先需要创建一个“桥接头”。 虽然从概念上看这似乎并不复杂,但在实践中,它实际上可能是一项艰巨的任务。

Swift 和 Objective-C 之间接口的另一组复杂性源于它们类型系统的固有差异。 Swift 从其他现代语言中汲取灵感,废除了nil的概念。 取而代之的是 Swift 的可选类型。 例如,仅当文件已存在时才打开文件的方法的返回类型为File? (而不仅仅是File )在 Swift 中。 通过跟踪类型可选的所有地方,Swift 编译器可以有效地避免遇到可怕的“空指针错误”。 当然,除非你调用的是 Objective-C。 由于 Objective-C 对不返回nil没有做出这样的保证,Swift 有一个特殊的类型,称为Implicitly Unwrapped Optionals ,在调用 Objective-C 代码时使用。 这些类型可以被视为 Swift 语言中的可选项,以及存在检查所需的所有伴随开销。 或者,它们可以与任何非可选类型一样使用,但是如果 Objective-C确实返回nil ,您最终会出现运行时错误,因此您会失去一些 Swift 的编译时安全保证。

最后,在 Swift 和 Objective-C 之间进行编程时需要考虑的稍微微妙的不匹配与这两种语言中对象和类的创建方式有关。 Objective-C,由于其动态特性,利用动态调度来调用对象上的方法(通过objc_msgSend )。 Swift 当然可以使用动态调度,但由于它是静态类型的,它还可以选择使用vtable来存储每个方法的函数指针。 Swift 使用这两种机制中的哪一种取决于几个因素。 平面旧 Swift 对象将使用vtable机制,除非类中的类或方法使用@objc Swift 属性进行注释。 从 Objective-C 类继承的 Swift 类将对继承的方法使用动态调度,但不会对子类引入的任何新方法使用动态调度(不过,您可以再次通过@objc属性强制使用动态调度)。 无论如何,Swift 代码将始终能够使用 Swift 类,但 Objective-C 代码只能使用已正确注释的 Swift 对象和方法。

比 Objective-C 更快?

当 Apple 推出其产品时,特别强调 Swift 的好处之一就是它的速度。 当您考虑到 Apple 不愿从 Objective-C 切换到更高级语言的一个原因时,这是可以理解的,因为 Objective-C 本质上是 C 的扩展,能够创建更快、更高效的程序而不是像 Python 或 Ruby 这样的东西。 即便如此,就绝对性能而言,Objective-C 也不是火箭飞船,这在很大程度上要归功于动态类型。 因此,随着 Swift 采用静态类型系统,人们会期望 Swift 至少应该与 Objective-C 一样快,或者更快。

当然,俗话说,“谎言分三种:谎言、该死的谎言、基准。” (或类似的东西……)当然,Swift 语言可能运行得更快的原因有很多。 不幸的是,似乎 Swift 使用 Apple 的 ARC(自动引用计数)技术进行内存管理的方式有时会导致 Swift 的编译器生成的程序明显变慢,尤其是在优化设置较低的情况下(例如您可能在开发过程中使用的程序)。 好消息是,对 Swift 的改进似乎在不断解决这个问题,因此在不久的将来,Swift 生成可执行文件的速度可能至少与 Objective-C 一样快或更快。

不过,Swift 的速度还有另一个警告。 Swift 的全部意义在于,开发人员不会编写与他们在 Objective-C 中编写的代码相同的代码。 这对性能意味着什么? 嗯,这当然意味着比较 Swift 和 Objective-C 之间的性能比简单的基准测试所能揭示的要复杂得多。 这也意味着比较生成的可执行文件的绝对运行时性能只能说明一半。

每个人都想要快速的程序,但开发速度通常同样重要——如果不是更重要的话。 一种更具表现力的语言,能够以更少的代码行完成更多的工作,在这方面可能是一个巨大的好处。 另一方面,在编辑-编译-运行-调试周期占据程序员大部分时间的编译语言中工作时,慢速编译器确实会损害生产力。 虽然证据主要是轶事,但似乎 Swift 编译器目前的速度慢到令人讨厌,尤其是在处理使用 Swift 高级类型系统的代码时。 一个小组甚至发现编译速度的问题足以促使他们切换回 Objective-C。

编译器

说到 Swift 编译器,在考虑切换到新的 Swift 语言时,它本身就是更多警告的来源。 除了编译速度之外,随着 Swift 从 Apple 的一小部分开发人员中脱颖而出并被大众所释放,编译器在压力下开始出现裂缝。 甚至还有一个完整的 GitHub 存储库专门用于收集会导致 Swift 编译器崩溃的代码示例。

还有一个问题是 Swift 编译器将如何改变。 GitHub 上的另一个项目正在收集社区关于 Swift 可能会发生哪些变化的猜测和分析。 例如,自定义运算符会给解析器带来很大的压力。 最初,Swift 中的自定义运算符不能使用问号 (?) 字符。 虽然这一问题已在最新的 Swift 版本中得到修复,但不断增长的 Swift 开发者社区不断涌入请求,以便在可以被视为有效的自定义运算符方面获得更大的灵活性。

每当您听到一种语言的解析器在不断变化时,它都应该让您停下来。 语言的解析器是编程语言的核心和灵魂。 在可以应用任何语言语义来赋予代码含义之前,解析器首先确定什么是有效代码,什么是无效代码。 因此,令人鼓舞的是,Apple 已承诺确保 Swift 具有一定程度的运行时兼容性。 但是,这并不一定保证 Swift 代码无需为每个新版本的 Xcode 和/或 iOS 重新编译即可运行。 它也不保证您不需要重写部分 Swift 代码来保持与 Swift 未来版本的兼容性。 但同样,Apple 承诺让这个过程尽可能轻松,这至少是一些小小的安慰。

社区

一些有史以来最糟糕的编程语言(将保持无名)一直受到鼓舞,早在常识认为它们应该仅靠各自社区的力量就应该被归入失败技术的垃圾箱之后很久。 同时,由于缺乏一个社区而未能占据一席之地的真正优秀的编程语言的集合数不胜数。 强大的社区制作教程,在 Stack Overflow 上回答问题,在线或亲自参加会议分享故事、提示和技巧,并相互编写和共享有用的库。 在选择用于项目的语言时,社区绝对是需要考虑的因素。

遗憾的是,iOS/Objective-C 社区在友好和热情方面并没有最好的声誉。 这种情况正在逐渐发生变化,开源在 Objective-C 开发中扮演着越来越重要的角色。 尽管如此,在这个早期阶段,很难说 Swift 社区未来会是什么样子。 它是否主要由孤立的开发人员组成,只使用官方的 Apple API 和他们自己的私人代码集合? 或者它会是一个充满活力的团体社区,分享技巧、窍门和有用的图书馆?

社区角色的另一个方面是 Swift 开发人员本身的角色。 编程的总体趋势是从专有编程语言和平台转向开源解决方案。 开源开发,尤其是在编程语言和运行时级别,可能是一个真正的优势。 虽然 Swift 开发人员多次表示他们的意图是完全开源 Swift 语言和运行时,但这种情况尚未发生,因此需要谨慎。

也就是说,Swift 背后的开发人员与长期运行的 LLVM 项目背后的一些开发人员相同。 LLVM 并不是一个完美的类比,因为它是作为伊利诺伊大学厄巴纳-香槟分校的一个项目在开放中开始的。 但值得称赞的是,核心开发人员仍然非常开放并与社区互动,即使他们中的大多数人已经过渡到为 Apple 工作。 可以完全合理地期望 Swift 语言将继续(大部分)以开放的方式开发,尽管来自社区的补丁和功能建议是否会进入该语言还有待观察。

我应该学习 Swift 吗?

当然,这里没有“一刀切”的答案。 与往常一样,为工作选择正确的工具需要对相关项目的所有细节有深入的了解。 当然,此时此刻,Objective-C 仍然是 iOS 开发的“安全”选择,但 Swift 绝对值得考虑。

然而,Swift 给 iOS 开发带来的最重要的变化是,许多开发人员将第一次问自己一个问题:“我应该使用什么语言?” 鉴于 Apple、Objective-C 和 iOS 平台的历史,仅此一项更改就相当令人兴奋,尤其是考虑到选择不是二元的。 虽然 Apple 已经明确表达了他们的偏好,但整个 iOS 开发者社区多年来一直在努力工作,已经为这个问题提供了更多可能的答案。