不过,iOS 和 Mac OS X 对 JPEG 2000 的支持相当慢,所以使用 JPEG 2000 并不是一个好选择。还有相当多的证据表明,这种性能上的缺陷并不是没有人尝试去修复,而是被现有的格式和技术手段所制约住了。所以这种方法似乎相当令人生畏,尽管我们的需求允许使用较少层次的金字塔简单实现,也可以使用其他的压缩机制来编码这些基本图像。
Mac 和 iOS 客户端的数据模型使用 Core Data 来构建,此外也用来关联 UI 组件。正如我们在第 12 章所看到的那样,对于少量数据和简单用例而言,Core Data 的表现还行,毕竟性能的要求并不高。但是在处理中等或者大量数据的时候,保持高性能就变成了极大的挑战,开发团队发现他们得创建更复杂、同时也更加脆弱的权衡措施,才能够保证 Core Data 不会由于 I/O 而阻塞主线程。
URI 是结构化的。例如,示例 17.2 中的第一个 URI 引用了 id 2 列表中的 id 3 对象所表示的任务。第二个 URI 表示 id 2 列表对象。第三个 URI 是一个数组,表示包含在 id 2 列表当中的所有任务。最后一个 URI 指示表示 id 为 3 的一个任务,并没有提供任何列表 id。在我们目前的实现中,这会在所有列表中搜索满足此条件的任务。
顾名思义,WLRESTOperationQueue 由一个 REST 操作队列组成,而每个操作又由一个 WLObjectReference 和一个 REST 动词(GET、PUT、DELETE)组成,该动词用于告知目标应该对引用执行何种操作。操作的含义取决于具体的目标。对于磁盘存储而言,如果收到了 PUT 就意味着要将这个由 URI 指定的对象存储到磁盘;对于 Web 接口而言,则是意味着发送 HTTP PUT 请求给后端。
自动合并的工作方法就是监视队列的深度。对于进入到队列当中的 URI 而言,随着队列越来越长,合并级别也将逐步增加,URI 后面的元素移除得也越来越多。如果将合并级别设置为默认值,那么诸如 task://container/2/id/3 之类的 URI 将原样进入到队列当中,并且合并只会影响到特定任务的更改。
如果将自动合并的合并级别设置为 1,那么就会从 URI 后面移除一个元素,仅仅只留下前面的容器:task://container/2。这会造成两种影响:一方面,当前 UI 中的整个列表会全部刷新,而不是针对某个特定任务进行更新;另一方面,这还会将列表当中所有独立的项目更新给合并在一起。因此,这就不会对列表当中的项目进行多次更新,因为我们对整个列表执行了更新。
一项调查结果出乎意料:Mac OS X 新版本下,某个安装程序按照预期的步骤执行安装数千个小文件,竟然出现了进度减慢的神秘现象。在新版本下,安装程序速度减缓了几倍,几乎降了一个数量级。I/O 速率比磁盘子系统慢了很多,CPU 的使用率可以忽略不计,所以看起来好像没什么瓶颈可以用来解释这种性能下降的情形。
节流显示
在使用了大量工具和抓耳挠腮之后,终于发现安装器提供显示了状态更新信息。它正在显示每个安装文件名称,为了确保用户有机会看到每一个文件名,每次都会刷新屏幕上的内容。这样能满足用户了解过程进度的渴望,却与 Mac OS X 图形子系统的节流机制相冲突,限制图形的更新频率,现在设置成了大约 60 Hz。试着更频繁的刷新屏幕,就能轻而易举地阻塞你的程序,正如示例 16.1 所示。
绘制缩略图的第一个方案,如图 16.3 所示,以 “缩略图” 为主。一张缩略图实际上就是一张从源文件中生成的小图片,我们的 Windows 客户端直接为每个页面创建了缩略图图片,保存在硬盘里。
Mac 团队认为他们应该也这样做,不过效果更好,因为 OS X 支持高质量的 PDF,苹果也引入了 CGImageSource CreateThumbnailAtIndex() 方法,专门用于从硬盘中加载缩略图。那么最可能出什么纰漏呢?
额怎么说呢,使用该方法后所有东西都出错了:因为 PDF 是一种与分辨率无关的格式,每个 PDF “缩略图” 包含了全分辨率的 PNG,绘制到 PDF 需要解压 PNG,生成 PDF 后再重新压缩。这些 PDF 由于包含了太多细节信息,因此 “缩略图” 渲染速度也很慢,为每个 PDF 生成新的线程解决进程自身执行缓慢的问题。
如果笔记有数百页之多,每次打开软件的时候都要重新加载缩略图,这也太奇怪了。如果你愿意等那么长的时间,只要软件仍处于打开状态,这些缩略图总会存下来的。但是等的时间也太长了吧!如果这时候你关闭软件,然后重新打开,猜猜会发生什么?你又要重新等待缩略图加载!我不知道这个问题是否出现在 Windows 版本的软件中,不过在 Mac 版里确实出现了。
在本章,我们了解了图形性能和响应性。尽管底层绘制性能更容易测量,一直是开发者热衷讨论的话题,我觉得架构模式和特定领域的优化有更深远的影响。实际上,阻止高级优化的底层的技术限制,常常比单纯的低级优化有更深远的影响,在 model-view-controller 通信机制中更为明显,也和我们网络连接的设备更息息相关,因为我们可以快速更改 model 无需用户输入。我们会在下一章中寻找一种更容易理解的解决方案。
在 Mac OS X 上,有个专门用来调试图形性能的工具,叫做 Quartz Debug。图 15.3 显示了其主要菜单选项和帧率表盘。Quartz Debug 可以调试 Mac OS X 图形堆栈中的全局元素。它不仅会检测你的程序,还会检测所有正在运行的程序,包括 Quartz Debug 本身,最好在测试之前关闭或者隐藏其他正在运行的程序。
这些控件基于 OS X 的 NSView 类和 iOS 的 UIView,它允许用户扩展视图的层次结构。一个视图(view)表示屏幕上的一个矩形区域,可用drawRect:方法渲染,可处理用户的输入事件。这些高层级框架主要通过 Core Graphic 的 API 进行绘制方面的工作,Core Graphic 有时候也被叫做 Quartz。
另外一个与图形相关的主要 API 是 OpenGL,它主要用于 3D 图形应用中,例如一些 3D 游戏,由于这套 API 拥有对图形加速硬件的访问权限,也常常被其他的 API 所使用。除此之外,还有一些处理图片或者视频的 API,如 Core Image 和 Core Video,以及视频播放相关的 AVFoundation 或 Quick Time X,最新的框架还包括了用于 2D 游戏开发的框架 SpriteKit 和用于处理 3D 图形的高级框架 SceneKit。
在显示列表(display list)被图像系统持有且直接驱动显像管(CRT)成像的时代,保留模式(retained-mode)和即时模式(immediate-mode)的意义在于它们区分了两种不同风格的图形 API。在即时模式中,程序通过主动调用绘图 API 的方式进行渲染。而在保留模式中,程序不会主动调用绘图相关的 API ,而是通过更新 API 创建的对象这种方式来实现渲染的效果。
图 14.2 以三个几何图形为例来阐述二者之间的不同。图表上方是保留模式风格的 API,程序首先生成三个图形,这些图形会以某种数据结构或着数据库的形式被 API 所持有。如果想要改变粉色矩形的坐标,程序必须要记住该矩形,并且告诉 API 要移动该矩形。接着 API 就会担负起刷新屏幕并渲染该矩形到新的位置上的工作。图表下方是即时模式风格的 API,它没有保留模式那么复杂,它只需绘制两遍场景(scence)即可,粉色矩形一次是在旧的坐标上,一次是新的坐标上。
Quartz 和 OpenGL 这两个重要的图形 API 都是即时模式风格的 API,绘图命令可以直接发起并立即执行。虽然 OpenGL 将自己内部的 API 划分为了即时模式和保留模式,但从广义上来说,OpenGL 的 API 应该都是即时模式风格的 API。SceneKit 和 SpriteKit 属于保留模式风格的 API;你需要创建 nodes(节点)并将其添加到场景中,之后的过程中,我们只需要对节点进行操作即可。
乍一看,保留模式风格的 API 似乎更简单一些,尤其在图形对象的层级关系满足应用需求的时候。因此在许多场景中,一个简易的图形编辑器可以是这些 API 轻度封装后的产物。然而,现实中的大多数应用都有特定的应用场景和特定的数据模型,这也就是说通过业务对象模型(domain-model)和相关算法得到的图元也会缺乏共性。在这种情况下,我们可以选择继续抽象相关算法以便它能够处理不同类型的数据模型,也可以选择放弃保留模式,而投入到即时模式的怀抱中。
Mac OS X 平台上的第二个基础图形 API 就是 3D OpenGL API(iOS 上也叫 OpenGL ES)。OpenGL 最早是由 Silicon Graphics 开发出来的,它是一种与语言无关的、跨平台的 3D 图形 API,但是在后来它变成了一个开源标准。远远超越了现在的 PHIGS 开源标准,而其中的原因就是 OpenGL 与 Postscript,Quartz 一样,都是即时模式风格的图形框架,相比较与 PHIGS 这种保留模式风格的图形框架,OpenGL 的使用更加简单。
针对前面所说的情况,即使考虑到视网膜(retina)屏幕的存在。我们需要提供的像素数量也可以说是相对稳定的,iPhone 屏幕的像素数量在七十万到二百万之间,iPad 屏幕需要的像素数量接近三百万,iPad Pro 或者笔记本电脑的像素数量接近五百万。因此无论应用程序多么复杂,只要在每次刷新的过程中能够处理这么多的像素数,就代表你可以改变整个屏幕的内容。在大 O 表示法中,它的复杂度是 O(k)。
GPU 不仅在架构上拥有一定的优势,它还可以在图形计算中充分发挥自身并行计算的能力,这是以芯片上有大量的晶体管为前提做保障的。虽然 CPU 也有相似的晶体管数量,但是 CPU 却并不具备相同的并行能力。
所以,相比于 CPU 设计者需要采取更加精密的方案才能让 CPU 在执行大量串性指令的时候得到小幅的性能提升,而利用额外的硬件资源就会让整体性能的提升近似于线性增长,例如让 GPU 分担一部分的计算量。GPU 和 CPU 在处理串行指令上的区别是造成它两性能差距的主要原因之一(在适当的计算负载下),但是 GPU 的性能提升曲线更为陡峭,意味着 CPU 和 GPU 的性能差距每年都会扩大。
从 Quartz 到 Core Animation
Mac OS X 和 iOS 的图像 API 最开始只有基于 CPU 渲染的 Quartz,随后 Quartz Extreme,Quartz GL,以及 Core Animation 等图像框架逐渐加入到这个大家庭中。驱动这些 API 演变的不只是基于 OpenGL 的游戏,还有充分利用现代 GPU 潜能进行系统级别图形渲染的目标。
由于窗口管理者的存在,不管是即时模式还是保留模式,Mac OS X 上的每个图形 API 最后都变成了保留模式的 API,具有窗口位图和保留状态,具备保留模式 API 的所有优势:窗口可以随意移动,移动的过程可视化,完全由 Window Manager 控制。这和之前的视窗系统(windowing systems)不同,也不像是 AppKit 或 UIKit 中的视图层级结构,无需客户端代码来重绘显示的部分,因此即使进程不响应,窗口的操作总是非常平滑的。
在 Mac OS X 10.2 引入了 Quartz Extreme 库,这个库为系统添加了一些图形硬件加速的能力。系统中的每个窗口都变成了 OpenGL 里的矩形,窗口的内容(由 Quartz 或其他图形 API 提供)都变成了 OpenGL 的纹理,这些纹理被映射到了相应的矩形中。每个窗口的内容都由合适的 API 进行绘制,然后再使用 OpenGL 和图形硬件将内容整合到位图窗口(bitmap window)中。
这种改变不仅更好地利用了显卡的性能,对于许多操作而言,也完全消除了 CPU 的负载:为了移动窗口,视窗管理者(window server)只需改变矩形的坐标,想要将窗口置前或置后,只需调整矩形的 z 值。
其次,PCH 会引发命名空间被污染的问题,因为 PCH 引入的头文件会出现在你代码中的每一处,而这可能会是多于的操作,比如 iAd 应当出现在一些与广告相关的代码中,它完全没必要出现在帮助相关的代码中(也就是与广告无关的逻辑),可是当你把它放到 PCH 中,就意味组件里的所有地方都会引入 iAd 的代码,包括帮助页面,这可能并不是我们想要的结果!
Associates public, private, or project header files with the target. Public and private headers define API intended for use by other clients, and are copied into a product for installation. For example, public and private headers in a framework target are copied into Headers and PrivateHeaders subfolders within a product. Project headers define API used and built by a target, but not copied into a product. This phase can be used once per target.
Public: The interface is finalized and meant to be used by your product’s clients. A public header is included in the product as readable source code without restriction. Private: The interface isn’t intended for your clients or it’s in early stages of development. A private header is included in the product, but it’s marked “private”. Thus the symbols are visible to all clients, but clients should understand that they’re not supposed to use them. Project: The interface is for use only by implementation files in the current project. A project header is not included in the target, except in object code. The symbols are not visible to clients at all, only to you.
我们可以看到,private_header_files 在这里的含义是说,它本身是相对于 public 而言的,这些头文件本义是不希望暴露给用户使用的,而且也不会产生相关文档,但是在构建的时候,会出现在最终产物中,只有既没有被 public 和 private 标注的头文件,才会被认为是真正的私有头文件,且不出现在最终的产物里。
其实这么看来,CocoaPods 对于 public 和 private 的理解是和 Xcode 中的描述一致的,两处的 Private 并非我们通常理解的 Private,它的本意更应该是开发者准备对外开放,但又没完全 ready 的头文件,更像一个 In Progress 的含义。
Associates public, private, or project header files with the target. Public and private headers define API intended for use by other clients, and are copied into a product for installation. For example, public and private headers in a framework target are copied into Headers and PrivateHeaders subfolders within a product. Project headers define API used and built by a target, but not copied into a product. This phase can be used once per target.
Public: The interface is finalized and meant to be used by your product’s clients. A public header is included in the product as readable source code without restriction. Private: The interface isn’t intended for your clients or it’s in early stages of development. A private header is included in the product, but it’s marked “private”. Thus the symbols are visible to all clients, but clients should understand that they’re not supposed to use them. Project: The interface is for use only by implementation files in the current project. A project header is not included in the target, except in object code. The symbols are not visible to clients at all, only to you.
我们可以看到,private_header_files 在这里的含义是说,它本身是相对于 public 而言的,这些头文件本义是不希望暴露给用户使用的,而且也不会产生相关文档,但是在构建的时候,会出现在最终产物中,只有既没有被 public 和 private 标注的头文件,才会被认为是真正的私有头文件,且不出现在最终的产物里。
其实看起来,CocoaPods 对于 public 和 private 的官方解释是和 Xcode 中的描述一致的,两处的 Private 并非我们通常理解的 Private,它的本意更应该是开发者准备对外开放,但又没完全 Ready 的头文件,更像一个 In Progress 的含义。
// this is part of Gemfile source 'http://sakgems.sankuai.com/' do gem 'cocoapods-hmap-prebuilt' gem 'XXX' ... end // this is part of Podfile target 'XXX' do plugin 'cocoapods-hmap-prebuilt' pod 'XXX' ... end
苹果公司在它的 API 文档中专门用了一段文字来解答大家的疑惑,这段文字的标题为《Handling View-Related Notifications》,在这里我们直接引用原文:
When the visibility of its views changes, a view controller automatically calls its own methods so that subclasses can respond to the change. Use a method like viewWillAppear: to prepare your views to appear onscreen, and use the viewWillDisappear: to save changes or other state information. Use other methods to make appropriate changes. Figure 1 shows the possible visible states for a view controller’s views and the state transitions that can occur. Not all ‘will’ callback methods are paired with only a ‘did’ callback method. You need to ensure that if you start a process in a ‘will’ callback method, you end the process in both the corresponding ‘did’ and the opposite ‘will’ callback method.
这里很好的解释了所有的 will 系列方法和 did 系列方法的对应关系,同时也给我们吃了一个定心丸,那就是在 appearing 和 disappearing 状态之间会由 will 系列方法进行衔接,避免了状态中断。这对于连续 push 或者连续 pop 的情况是及其重要的,否则我们无法做到 “谁修改,谁复原”的原则。
这里稍微提一下的,Tom 是 SwiftNIO 的核心开发,同时在 SSWG(Swift Server Work Group) 项目中也是主要的发起者,而 Saleem 是 Swift to Windows 的核心发起者,这两个变动结合着最开始的三个大方向,可以看出整个核心团队是言行一致的。
另外关于 Swift 6 的公布时间,Ted 的原话是这样的:
Instead of announcing a specific timeline for “Swift 6”, the plan is for the community to be a part of seeing these efforts progress, with focused efforts and goals, and we release Swift 6 when those efforts culminate.
所以这样看来,Swift 6 还是有一段时间才能与我们见面,毕竟人家说了 when those efforts culminate!
同时像 Google 的 Firebase 在其 RoadMap 里也明确指出了将更加关注 Swift 的使用体验并开始了部分改造。
相信不久的将来,会有越来越多的厂商加入到 Swift 的社区中,除了 Swift 是未来 这样人人都懂的道理以外,这两年新增的特性,例如 ABI 稳定,Module 稳定,以及 SPM 对 binary 组件的支持,都会导致厂商的态度改变,尤其是那些需要使用非源码形式发布组件的厂商,毕竟这些特性从根本上解决他们面临的工程问题。
在 Swift 独占方面,新增了 3 个 SDK,分别是 Developer Tools Support,System,WidgetKit,其中 System 是个用于进行底层文件操作(low-level file operation)的库,似乎这也是 Apple 的首个用 Swift 编写的系统底层库(PS:如果说的不对,还请各位读者指正);另外一个想说的重点就是 WidgetKit,这也是首次 Apple 在推广系统新特性的时候强制要求开发者必须使用 Swift 技术,这个策略我认为还是十分高明的,它为 Swift 技术的推广和应用找到了新的出路。
从表面看,除了去年提到的 BAT 之外,今日头条,快手,滴滴,支付宝,京东,拼多多等一众应用也都在今年完成了 Swift 的初体验,比较有意思的是美团系的应用(美团,大众点评,美团外卖)目前似乎还没有任何动静。
虽然国内的 Swift 混编占比变高,但我个人认为,这并代表国内大部分公司要开始转型 Swift 技术了,这样的变化,主要是因为去年 Apple 新增的 Widget 技术导致的,因为想开发 Widget 必须使用 Swift 相关的技术,而上面提到的各个应用,大多都提供了相应的小组件。
如果历史有可以借鉴的地方,那么 2021 年的国内 Swift 占比(59%)与 2019 年的国外占比(78%)还算比较接近,至少不像去年(30% 和 82.3%)的差距那么大,那么按照这个趋势发展的话,我们是否可以预言在未来的 3-5 年内,国内的 Swift 混编应用占比也将达到 90% 左右?
PS:在写这篇文档的时候,发现微博也支持小组件了,所以估计上面的这个数据又得增加 1% 了。
总结与展望
在做完了今年的调研后,我们能得出什么结论呢?
虽然看起来现阶段的 Swift 还是在一个积累的过程,但随着 WidgetKit 这个标志性的 SDK 诞生,我相信这个发展阶段会从积累阶段慢慢转向发展期,毕竟现在 ABI 稳定了,Module 稳定了,对二进制组件的支持也有了,还有 Swift 语言本身的版本变化也逐渐稳定了,这些都给与了 Swift 很好的支持。
Swift 的发展方向绝不只是为了 Apple 生态体系内的那点事儿,这个从社区的规划也好,从 Timac 的那几篇分析文章也好,我们都可以看出它在多元发展上的决心,Swift 真的很想破圈。
国内的 Swift 发展被去年的 iOS 14 新特性给盘活了,WidgetKit 功不可没,虽然还不能给出大部分公司都将转型的结论,但至少绝大部分互联网的头部公司已经兼容了 Swift 的开发,这是一个好的开始,相信在可见的未来,Apple 的转型决心必然会让国内的公司会更加重视这方面工作的重要性。
publicfuncrun()throws { guard arguments.count > 1else { throwError.missingFileName } // The first argument is the execution path let fileName = arguments[1]
OPTIONS: --include-counter Include a counter with each repetition. -c, --count <count> The number of times to repeat 'phrase'. -h, --help Show helpfor this command.
import Foundation import XCTest import Files import CommandLineToolCore
classCommandLineToolTests: XCTestCase{ functestCreatingFile()throws { // Setup a temp test folder that can be used as a sandbox let tempFolder = Folder.temporary let testFolder = try tempFolder.createSubfolderIfNeeded( withName: "CommandLineToolTests" )
// Empty the test folder to ensure a clean state try testFolder.empty()
// Make the temp folder the current working folder let fileManager = FileManager.default fileManager.changeCurrentDirectoryPath(testFolder.path)
// Create an instance of the command line tool let arguments = [testFolder.path, "Hello.swift"] let tool = CommandLineTool(arguments: arguments)
// Run the tool and assert that the file was created try tool.run() XCTAssertNotNil(try? testFolder.file(named: "Hello.swift")) } }
此外,还可以添加另一个测试,以验证在没有给定文件名或文件创建失败时是否抛出了正确的错误。
要运行测试,只需在命令行上运行 swift test 即可。
安装工具
现在我们已经构建并测试了我们的命令行工具!下面开始,我们会尝试安装它,并使它能够在任何地方运行。
要做到这一点,需要在 swift build 后面增加 release 的配置,也就是 -c relase 参数,然后将编译后的二进制文件移到 /usr/local/bin。
1 2 3
$ swift build -c release $ cd .build/release $ cp -f CommandLineTool /usr/local/bin/commandlinetool
Swift 和 Objective—C 的命名风格是有所不同,例如 Swift 的 API 是由基名(previousMissionsFlown)和参数标签(by)组成的,⽽ Objective—C 基本上只有参数标签(previousMissionsFlownByAstronaut),没有单独的基名,所以基名的信息会包含在第⼀个参数标签⾥,这也导致了 Objective—C 的方法名会显得略长一些。
为了解决 API 风格上的问题,Swift 会根据一些规则重命名,通常这个结果还不错,但这毕竟是计算机的审美结果,很难满足开发者的诉求。
例如某些开发者会认为 flown 应该是参数标签⾥的⼀部分,⽽不是 base name,因为这个⽅ 法获取的是以前的任务列表,它们是某个宇航员所执⾏的任务!
Clang 导入器(Clang Importer):Clang 导入器(在 lib/ClangImporter 中实现)负责导入 Clang 模块,并将导出的 C 或 Objective-C API 映射到相应的 Swift API 中。最终导入的 AST 可以被语义分析引用。
SIL 生成(SIL Generation):Swift 中间语言(Swift Intermediate Language,SIL)是一门高级且专用于 Swift 的中间语言,适用于对 Swift 代码的进一步分析和优化。SIL 生成阶段(在 lib/SILGen 中实现)将经过类型检查的 AST 弱化为所谓的「原始」SIL。SIL 的设计在 docs/SIL.rst 有所描述。
SIL 保证转换(SIL Guaranteed Transformations):SIL 保证转换阶段(在 lib/SILOptimizer/Mandatory 中实现)负责执行额外且影响程序正确性的数据流诊断(比如使用未初始化的变量)。这些转换的最终结果是「规范」SIL。
SIL 优化(SIL Optimizations):SIL 优化阶段(在 lib/Analysis、lib/ARC、lib/LoopTransforms 以及 lib/Transforms 中实现)负责对程序执行额外的高级且专用于 Swift 的优化,包括(例如)自动引用计数优化、去虚拟化、以及通用的专业化。
LLVM IR 生成(LLVM IR Generation):IR 生成阶段(在 lib/IRGen 中实现)将 SIL 弱化为 LLVM LR,此时 LLVM 可以继续优化并生成机器码。
从原文的内容里,我们可以看到 Swift 编译器主要是在前端部分增加了一些环节,主要是在语义分析和中间代码生成的过程中增加了几个步骤:
对协议,泛型能力进一步扩展,开始支持 Linux,随后出现了以 Swift 语言为核心的后端框架 Perfect,Vapor,Kitura
Swift 3.0 ~ 3.3.1
8.x
2016
发布了 Swift Package Manager,同时以 GCD,Core Graphics 为代表的基础库 API 风格发生了大幅度转变,摆脱了 Objective-C 时代的烙印
Swift 4.0 ~ 4.1.3
9.x
2017
在整体的语法,使用和理念上基本定型,提出了 Codable 协议,同时 Xcode 的 Swift Syntax Mirgration 的最低版本固定为 4
Swift 4.2 ~ 4.2.4
10.x
2018
Swift社区从邮件列表转向论坛,语言小幅升级,主要是功能完善,性能提升,同年 Swift for TensorFlow 发布并开源
Swift 5.0 ~ 5.0.3
10.2.x
2019
ABI 稳定,iOS 12 开始内置 Swift 运行时
Swift 5.1 ~ 5.2
11.x
2020
新增 Property Wrapper ,Opaque Type 等新的语法功能,同年 WWDC 上,Apple 发布了 SwiftUI,Combine,Catalyst 等 Swift 语言的专属 SDK
Swift 5.3
质量和性能增强,增加对 Windows 和其他 Linux 发行版的支持。
结合着自己的 Swift 学习经历,不难发现:
在 Swift 4 之前,由于语言整体还没定型,确实存在着发一个新版本,学一门新语言的情况,但在 Swift 4 之后,Swift 变化变得收敛了许多,不过也出现了入门容易,精通难的情况,毕竟光 Swift 的语法糖数量就快赶上了 C++ 了。
语言排行榜
Swift 语言从诞生之日开始,就一直存在各种各样的争议:一方面的焦点在于 Swift 的应用领域还是集中在 Apple 生态下,让人觉得不够大气,毕竟新时代的语言就是要全能,另一方面的焦点就是 Swift 语言的变化太快,每个版本都是是全新的感觉,这让开发者意识到,东西虽好,但代码还是要一个个的自己改的。
不过随着时间的推移,Swift 在后端,人工智能,物联网上的解决方案和应用场景不断出现,它已经远远不在是一个只能在 Apple 生态下运行的语言,关于这个非常推荐看看 Onevcat 在 GMTC 2019 上的分享:在分歧中发展——2019,我们能用 Swift 做什么
ABI 在 Swift 5.0 的时候也终于稳定了,虽然 ABI 稳定是使用 binary 发布框架的必要非充分条件,但都 ABI了,module stability 也不会太远了,这些信号都让开发者的信心不断增强。
不过,光研究语言本身,是枯燥的,也不立体,我还是想把 Swift 用到一些具体的场景上,毕竟玩起来才有意思!
于是我想起了自己早年间立的一个 flag:尝试一次游戏开发。
所以我迅速下单买了 Ray Wenderlich 家的《2D Apple Games by Tutorials》一书,虽然是 Swift 4 和 iOS 11 的版本,但说实话 Swift 4 到 5 的变化算比较温和,另外教材里的 iOS 系统也只落后现实世界里两个版本,SpriteKit 整体也没有什么翻天覆地的变化,落后的内容补上两个季度的 WWDC 就好了,所以,学就完事了!
看完这本书后,我不得不说老外的教材真的很好,只是可惜这书以后不再更新了。
大概花了一个月的时间,陆陆续续的把《2D Apple Games by Tutorials》里面的代码和作业也都敲了一遍,自我感觉还不错,问题就来了,怎么把学的东西用起来呢?