备注:本文章是翻译,如果大家想看原文请点击链接,第一次翻译谢谢。
Swift3可能在2016年就要发布了,对于开发者来说Swift3在代码上做的重大的改变。
如果你还没有经常去GitHub上看Swift Evolution项目,你可能不知道在应用商店做了什么样的改变,它会如何影响你的代码在Swift3中,这篇文章将告诉你。
开始
今天Xcode8beta已经出了Swift3的预览版。虽然Swift3的开发进展跌宕起伏,然而未来几个月仍然会有不少的改变。Xcode的特性在2016年底才会真正的定下来,所以你不得不推迟Swift3的应用去发布到APP Store。
为了让开发者根据自己的条件迁移Swift3,苹果公司在Xcode8包含了小量的更新在Swift2.3中。如果你是一个开发者,在WWDC大会上发布的Swift2.3基本上和Swift2.2是相同了,除了支持更多新的SDK和Xcode新的特性外。如果你还没有迁移到Swift3,你就可以在Xcode8发布beta版时使用Swift2.3提交你的应用程序。
我建议你尝试我们讨论的新的功能在playground上,甚至运行你的项目在迁移的过程中,这样你就会知道什么正在发生改变。但是你不能发布你的应用程序到APP Store,直到Xcode8发布beta版和Swift3出最终版,你也许会考虑为迁移你的代码到Swift3直到这个版本稳定。
迁移到Swift3
当切换到Swift3中时,你可能会注意到每个文件都需要改变!这主要是因为,大部分Cocoa API命名已经改变了。或者更精确,API的命名是相同的,但是一个命名是Object-C是恰当的,一个命名对于Swift是恰当的。Swift3将会使Swift写起来更加自然在以后的开发中。
苹果公司已经提供了迁移助手在Xcode8中,它能够出色的一举列出大部分的改变。所以你不必手动的做这些迁移工作。
你能够直接转换Swift2.3或者Swift3。如果你需要备份,你能够在Xcode导航条上选择
Edit>Convert>To Current Swift Syntax….
编译器会自动转换相同的编码。如果你调用了就得API方法,这编译会提供修复选项,帮助你选择正确的API。
最后的消息是Swift3将会是最后一个源代码的改变。所以很期待,你可能佳慧保持Swift代码从一个版本到另一个版本。然而Swift的核心团队不能预测未来,他们已经承诺即使他们改变的核心的代码,他们也会提供一个启用周期。这意味着Swift已经实现了平稳的改变,这将鼓励更多的企业使用Swift。
也就是说,要达到二进制平稳的发展的目标还没有达到。你会看到更多的影响在本文的末尾。
Swift演变的方案
自从Swift开源以来,社区成员为了改变Swift提交了超过100多个解决方案。其中大量的(超过70)的讨论和修改意见被采纳。那些被拒绝的提案已经引起了激烈的讨论。但是,归根结底,Swift核心团队有所有提案的最后决定权。
Swift的核心团队和社区开发者之间的合作非常好。事实上,在GitHub上Swift已经收获了30000颗星。几乎每周都有新的方案提交,这样一周一周的更新。即使是苹果的工程师也会为Swift的改变在GitHub上提交他们的提案。
在下面的部分你将会看到链接标记例如[SE-0001]。这些是Swift演进方案的数据记录。这里包括已经提交的解决方案编号以及将会在Swift3最终版本中采纳的。每一个提案都有链接,这样你就可以看到每一个提案的详细改变过程。
API的改变
在Swift3中最大的更新涉及到标准库中采用夸库命名的一致约定。开发团队已经制定了Swift3的这些规范在API 涉及指南中。这些设计对于一个新的成员来说具有搞的可读性和可接受性。Swift的核心团队坚持认为“好的设计总是考虑调用者”。他们尽可能带来更加清晰的使用点。事不宜迟,这些改变最大可能会影响你。
第一个参数标签
让我们开始改变你每天使用Swift的使用习惯。
除非你要实现它,否则在函数和方法的第一个参数前面总是有一个标签。以前当你调用一个方法或者函数时你省略了一个参数标签[SE-0046]:
// old way, Swift 2, followed by new way, Swift 3
"RW".writeToFile("filename", atomically: true, encoding: NSUTF8StringEncoding)
"RW".write(toFile: "filename", atomically: true, encoding: NSUTF8StringEncoding)
SKAction.rotateByAngle(CGFloat(M_PI_2), duration: 10)
SKAction.rotate(byAngle: CGFloat(M_PI_2), duration: 10)
UIFont.preferredFontForTextStyle(UIFontTextStyleSubheadline)
UIFont.preferredFont(forTextStyle: UIFontTextStyleSubheadline)
override func numberOfSectionsInTableView(tableView: UITableView) -> Int
override func numberOfSections(in tableView: UITableView) -> Int
func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView?
func viewForZooming(in scrollView: UIScrollView) -> UIView?
NSTimer.scheduledTimerWithTimeInterval(0.35, target: self, selector: #selector(reset), userInfo: nil, repeats: true)
NSTimer.scheduledTimer(timeInterval: 0.35, target: self, selector: #selector(reset), userInfo: nil, repeats: true)
记住如何去使用介词,例如:“of”,“with”和“in”。这些都是优化可读性的部分。
如果一个方法读起来能让调用者很清楚,根本不需要介词的介入。你应该明确排除不用下划线做第一个参数名:
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { ... }
override func didMoveToView(_ view: SKView) { ... }
总之参数的命名应该更让调用者明白和更容易理解。
省略不必要的单词
在苹果之前的库迭代中,方法包含了返回值的名称。由于Swift是类型检查语言,所以这些都不是很必要了。Swift团队花了很多时间去过滤这些重复的命名。
本地Swift的API已经考虑怎么转换Object-C的类库[SE-0005]:
// old way, Swift 2, followed by new way, Swift 3
let blue = UIColor.blueColor()
let blue = UIColor.blue()
let min = numbers.minElement()
let min = numbers.min()
attributedString.appendAttributedString(anotherString)
attributedString.append(anotherString)
names.insert("Jane", atIndex: 0)
names.insert("Jane", at: 0)
UIDevice.currentDevice()
UIDevice.current()
Modernized GCD and Core Graphics
据说旧的API不会发生改变,GCD和Core Graphics大部分都得重写。
Grand Central Dispatch大部分是作为异步任务像大量的计算或者请求服务器。这些异步线程防止用户界面被卡死。该libdispatch库用C编程语言,并始终用一个C风格的API。这些API现在仍然使用在Swift中[SE-0088]:
// old way, Swift 2
let queue = dispatch_queue_create("com.test.myqueue", nil)
dispatch_async(queue) {
print("Hello World")
}
// new way, Swift 3
let queue = DispatchQueue(label: "com.test.myqueue")
queue.async {
print("Hello World")
}
同样,在之前Core Graphics也是使用C写的,并且调用起来很麻烦,现在有了新的方式可以调用[SE-0044]:
// old way, Swift 2
let ctx = UIGraphicsGetCurrentContext()
let rectangle = CGRect(x: 0, y: 0, width: 512, height: 512)
CGContextSetFillColorWithColor(ctx, UIColor.blueColor().CGColor)
CGContextSetStrokeColorWithColor(ctx, UIColor.whiteColor().CGColor)
CGContextSetLineWidth(ctx, 10)
CGContextAddRect(ctx, rectangle)
CGContextDrawPath(ctx, .FillStroke)
UIGraphicsEndImageContext()
// new way, Swift 3
if let ctx = UIGraphicsGetCurrentContext() {
let rectangle = CGRect(x: 0, y: 0, width: 512, height: 512)
ctx.setFillColor(UIColor.blue().cgColor)
ctx.setStrokeColor(UIColor.white().cgColor)
ctx.setLineWidth(10)
ctx.addRect(rectangle)
ctx.drawPath(using: .fillStroke)
UIGraphicsEndImageContext()
}
枚举
另外一种你的Swift编码的方式的转变是lowerCamelCase替代了枚举类型。这使他们和其他属性更加一致-或者值[SE-0006]
// old way, Swift 2, followed by new way, Swift 3
UIInterfaceOrientationMask.Landscape
UIInterfaceOrientationMask.landscape
NSTextAlignment.Right
NSTextAlignment.right
SKBlendMode.Multiply
SKBlendMode.multiply
UpperCamelCase现在只保留为类型和协议名称,虽然这会花些时间去适应,但是Swift团队正努力让他们保持一致。
方法的返回值或者修改
标准库也越来越与动词和名词方法命名更加一致。你的命名依据你的函数的影响或者动作。经验法则是,如果它包括像一个后缀“-ed”或“-ing”,则认为该方法作为名词。一个名词方法返回一个值。如果它不具有后缀,那么它很可能是一个动词。这些“动词”的方法执行动作上的修改。这也被称为到位修改。有几种对遵循此名词/动词惯例的方法。下面是其中的几个[SE-0006]:
customArray.enumerate()
customArray.enumerated()
customArray.reverse()
customArray.reversed()
customArray.sort() // changed from .sortInPlace()
customArray.sorted()
下面是他们在动词的一个片段:
var ages = [21, 10, 2] // variable, not constant, so you can modify it
ages.sort() // modified in place, value now [2, 10, 21]
for (index, age) in ages.enumerated() { // "-ed" noun returns a copy
print("\(index). \(age)") // 1. 2 \n 2. 10 \n 3. 21
}
函数类型
函数声明和函数的调用一直要求在括号里面有参数:
func f(a: Int) { ... }
f(5)
然而当你使用函数类型作为参数本身时,你也许会像下面这么写:
func g(a: Int -> Int) -> Int -> Int { ... } // old way, Swift 2
你会发现它读起来很困难,参数的结尾和返回值得开始是在哪呢?然而Swift3正确定义了这个函数在[SE-0066]:
func g(a: (Int) -> Int) -> (Int) -> Int { ... } // new way, Swift 3
现在参数列表用括号包围,随后返回类型。事情更清楚,因此,功能类型更容易识别。这里有一个更强大的比较:
// old way, Swift 2
Int -> Float
String -> Int
T -> U
Int -> Float -> String
// new way, Swift 3
(Int) -> Float
(String) -> Int
(T) -> U
(Int) -> (Float) -> String
附加的API
虽然Swift3最大的更新已经被现有的API更新,但是仍然有很多Swift社区努力的工作-包括提供更好的附加API。
访问包含类型
当你定义一个静态的属性或者方法是,你总是直接用类名去调用:
CustomStruct.staticMethod()
如果你写代码使用上下午类型,你仍然需要包括这些命名类型在你去调用这些静态方法时。为了使调用更清楚,你能使用Self去获得包含类型。大写'S'指的是自我的类型,而小写字母“S”指的是自我的实例。
下面是它是如何工作在这个动作中[SE-0068]:
struct CustomStruct {
static func staticMethod() { ... }
func instanceMethod()
Self.staticMethod() // in the body of the type
}
}
let customStruct = CustomStruct()
customStruct.Self.staticMethod() // on an instance of the type
内联序列
sequence(first:next:)和sequence(state:next:)整个函数都返回内敛序列。你给他们一个初始值或可变的状态,他们将会通过来加载来应用这个课程[SE-0094]:
for view in sequence(first: someView, next: { $0.superview }) {
// someView, someView.superview, someView.superview.superview, ...
}
可以通过使用前缀操纵[SE-0045]约束序列:
for x in sequence(first: 0.1, next: { $0 * 2 }).prefix(while: { $0 < 4 }) {
// 0.1, 0.2, 0.4, 0.8, 1.6, 3.2
}
Miscellaneous Odds and Ends
- #keyPath()就像#selector(),并帮助你在强类型的API战胜错别字
- 你现在调用pi使用实例类型像这样:Float.pi,CGFloat.pi。大部分情况编译器能够获得引用类型:
let circumference = 2 * .pi * radius[SE-0067] - The NS 前缀已经被移除在老的方法类型中,你现在能使用Calendar, Date代替NSCalendar和NSDate。
改善工具
Swift是一个开发语言,写代码大部分都使用好用的开发工具例如苹果提供的Xcode!使用工具会影响你们每天写Swift代码的效率。
Swift3修复了一些bug在编译器和IDE的功能使用中。它也提高了错误和警告消息的精度,正如你所料,每个版本的发布Swift将会变得更快:
- 通过改善字符串哈希能够提高三倍的速度在字典字符串中。
- 通过移动对象从一个堆到栈上有24呗的提高(有些情况下)
- 现在的编译器一次缓存多个文件(整个模块优化的情况下)
- 代码大小优化已经减少了Swift代码编译的大小。苹果的演示 Demobots减少编译大小到原来的77%
Xcode会自动推断本地的Swift接下来会做什么:
当你在一个API的方法上右击像sort(),它就会跳到对应的定义中,你能看到它的头文件定义。现在,正如你期望的一样在Xcode8中你能看到sort()是Array的扩展。
Swift Snapshots也会随着Swift的发展发布。他们提供了一个机会再和新语法合并之前,完全被集成在Xcode中。Xcode8能加载和运行Swift Snapshots在playground上。
Swift包管理器
开源的Swift提供了一系列开源的库例如语言,核心库,包管理器。总之这构成了我们所认为的Swift。Swift Package Manager用于定义您共享和导入项目斯威夫特任何代码的简单目录结构。
相似的包管理器你可以使用Cocoapods或者Carthage,Swift的包管理器将会下载依赖,编译他们,链接他们去创建库和可执行文件。Swift3第一次发布包含了Swift包管理器。有超过1000个库已经被支持,未来将会有更多的库支持,你将会看到更多的规范。
未来的新功能
上文已经提到Swift3的目标是让你的代码保持每个版本都会适配在未来,避免重大的改变。虽然这是真的,但是仍然会有一些浮动,版本发布的目标没到达,也就是说泛型和二进制应用的稳定性。
泛型增加将包括递归协议约束和使一个约束扩展符合一个新的协议(即,Equatable元件的阵列是Equatable)的能力。在这些功能完成之前,Swift不可能定义ABI的稳定性。
ABI稳定将允许与不同版本的编译的应用程序和程序库能够被链接和相互作用彼此。这是第三方库框架不提供源代码,因为Swift的新版本不仅要求他们更新自己的代码,而且还要他们重新编译他们的Framework.
此外,ABI稳定性会删除Swift标准库的二进制文件,作为目前与Xcode中创建的iOS和MacOS应用程序的情况下。现在的二进制文件被绑定运行在2M的额外空间上在未来的操作系统上。
总结一下,您现在可以保持你的源代码版本的升级,而是因版本编译的二进制兼容性还不在这里。
哪去哪从
作为社区的最佳实践Swift平稳的发展。虽然仍处于起步阶段,但是在未来还有很大的发展空间。Swift已经运行在Linux,在未来的设备上,你可以看到它运行在服务器上。从头开始设计语言固然有其优势,一旦打破ABI稳定性,将是罕见的。这是一个独特的机会,让无悔正确的选择。
Swift也在不断的扩大其影响面。苹果为它提供了好的发展平台。苹果的开发团队使用Swift开发了音乐应用,控制台,画板在Sierra上,Xcode的文档预览器,和新的Swift Playground应用在iPad上。
说到这,有一个很大的推动让非程序员学习Swift,无论在iPad上还是通过教育活动。
这里的重点是:Swift将会继续发展:更好的命名,代码阅读起来更清晰,有更好的迁移工具。如果你想更深的研究你可以观看WWDC session videos。
会有更多的关于Swift3的结论在2016年下半年。我们会持续更新在这里,请留意这些文章和书籍,视频。我们很期待Swift的改变。
哪部分Swift3的改变你更感兴趣?有什么你想要首先获得的?请在下面留言!