Swift 3的变化

英文水平有限,理解全靠feel。英文原稿:
What's new in Swift 3.0
提示1
这一次改变非常多,有一些是很小的细节。尽管如此,希望这个改变会使swift在未来变得越来越好,这意味着在以后的版本中改变会变小。
提示2
如果你没有阅读what's new in Swift 2.2 这个篇文章,你应该知道-一切废弃的方法已经删除,包括:++,—,c语言的循环,元组splat语法,等等

升级到Swift 3时,你会发现基本上每个文件都需要改动!之所以这样,是因为所有的 Cocoa API 名称都改变了。简而言之,API还是原来的 API,但这个 API 在 Objective-C 中是一种叫法,而在 Swift 中是另一种叫法。Swift 3的语法书写起来要更贴近于自然语言。
在Xcode 8中,苹果提供了Migration Assistant,它可以完成大部分的迁移工作。当然,仍然有一部分工作是需要你手动完成的。

API 的改变

Swift 3 中最大的改变是标准库中在每个库中都采用了统一命名方式。API Design Guidleines中包含了这些规则,核心团队在构建 Swift 3 时采用了这些规则,对新手来说,这高度增强了可读性和易用性。核心团队遵循的是"好的 API 设计应当总是从调用者的角度看待问题"的原则。他们努力让 API 简单易用。不再多说,让我们开始介绍这些对你来说非常重要的改变。

省略不必要的单词
在早期的苹果标准库中,方法名中会包含一个单词,用于表明方法的返回值。因为 Swift 编译支持类型推断,这种做法其实并不必要。核心团队尽可能过滤一切"噪音",因此将这些重复的单词都删除了,只留下方法名中最重要的部分。
让我们看看一些简单的例子:

// 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()

如你所见,这会使得方法名显著的简短!
这个改变对字符串的改变最大,特别是当有重复的时候。证明这一点的最好办法是并排显示之前和之后的代码,所以在下面的代码每一对的第一行是swift2.2,第二个行是swift3.0:

"Hello".stringByTrimmingCharactersInSet(.whitespaceAndNewlineCharacterSet())
"Hello".trimmingCharacters(in:.whitespacesAndNewlines)

"Taylor".containsString("ayl")
"Taylor".contains("ayl")

"1,2,3,4,5".componentsSeparatedByString(",")
"1,2,3,4,5".components(separatedBy: ",")

myPath.stringByAppendingPathComponent("file.txt")
myPath.appendingPathComponent("file.txt")

"Hello, world".stringByReplacingOccurrencesOfString("Hello", withString: "Goodbye")
"Hello, world".replacingOccurrences(of: "Hello", with: "Goodbye")

"Hello, world".substringFromIndex(7)
"Hello, world".substring(from: 7)

"Hello, world".capitalizedString
"Hello, world".capitalized

Warning: capitalized 仍然是属性,但是 lowercaseString 和uppercaseString 已经变成方法lowercased() 和 uppercased().

我选择了到目前为止的示例,因为转换到swift3改变不大,但有相当多的变化,非常重要——通常当方法变短,并不是很明显。For example, look at this code:

dismiss(animated: true, completion: nil)

在 Swift 2.2种:

dismissViewControllerAnimated(true, completion: nil)

事实上,completion: nil这个部分是可选的,所以你可以写成这样:

dismiss(animated: true)

类似的变化发生在prepareForSegue(),如下所示:

override func prepare(for segue: UIStoryboardSegue, sender: AnyObject?)

在枚举和属性中大写命名被小写取代

虽然和语法无关,我们使用类和结构体、属性、枚举是首字母大写的名字。但是一直遵循一个惯例:类、结构体和枚举使用首字母大写命名(MyStruct, WeatherType.Cloudy),属性和参数的名称使用首字母小写(emailAddress, requestString)。

在swift 3中,属性和参数的名称使用小写命名,比如在swift2.2中创建NSURLRequest使用NSURLRequest(URL: someURL),swift 3中会写成URLRequest(url: someURL),这意味着我们可以使用webView.request?.url?.absoluteString来获取webView 的URL。

以前还有一些不和谐的部分属性大写,比如:CGColor或CIColor,在swift 3中变成了cgColor和ciColor,所以你可以写类似的代码:

let red = UIColor.red.cgColor

另一个和过去的 Swift 代码不同的地方是,在枚举中定义的 case 值现在使用小驼峰命名法。这是为了和属性名或者变量名保持一致

//old way, Swift 2, followed by new way, Swift 3
UIInterfaceOrientationMask.Landscape
UIInterfaceOrientationMask.landscape
NSTextAlignment.Right
NSTextAlignment.right
SKBlendMode.Multiply
SKBlendMode.multiply

UpperCamelCase命名法现在只在类型名和协议名上使用。当你习惯这一切之后,Swift团队对于追求一致性的努力才没有白费。

swift导入C函数

有一些函数是用 C 语言编写的,提供了 C 风格的 API。这个 API 现在在 Swift 中被重新设计
swift 3介绍了C函数属性,在C函数导入swift中使用一些特别优化的方法。比如在swift2中:

let ctx = UIGraphicsGetCurrentContext()
let rectangle = CGRect(x: 0, y: 0, width: 512, height: 512)
CGContextSetFillColorWithColor(ctx, UIColor.redColor().CGColor)
CGContextSetStrokeColorWithColor(ctx, UIColor.blackColor().CGColor)
CGContextSetLineWidth(ctx, 10)
CGContextAddRect(ctx, rectangle)
CGContextDrawPath(ctx, .FillStroke)
UIGraphicsEndImageContext()

在swift 3中,CGContext可以视为一个对象,你可以调用它的方法,而不是一遍又一遍的使用CGContext,我们可以这样写:

if let ctx = UIGraphicsGetCurrentContext() { 
let rectangle = CGRect(x: 0, y: 0, width: 512, height: 512) 
ctx.setFillColor(UIColor.red.cgColor) 
ctx.setStrokeColor(UIColor.black.cgColor) ctx.setLineWidth(10) 
ctx.addRect(rectangle) ctx.drawPath(using: .fillStroke) 
UIGraphicsEndImageContext()
}

注意:在swift2.2和swift3.0 UIGraphicsGetCurrentContext()都是返回一个可选的CGContext,但是在swift3.0中使用这个方法,我们需要确保可以安全的打开。

还有一些C函数的改变如下:

CGAffineTransformIdentity
CGAffineTransform.identity

CGAffineTransformMakeScale(2, 2)
CGAffineTransform(scaleX: 2, y: 2)

CGAffineTransformMakeTranslation(128, 128)
CGAffineTransform(translationX: 128, y: 128)

CGAffineTransformMakeRotation(CGFloat(M_PI))
CGAffineTransform(rotationAngle: CGFloat(M_PI))

动词和名词

这部分可能有一些人会开始困惑,这很遗憾,因为这个很重要!下面是一些swift API指南:

标准库中对方法名中使用动词和名词的规定也更加统一。你应当根据这个方法会导致什么后果或者要采取一些动作来进行方法命名。首要原则是如果这个方法名中包含"ed"或"ing"后缀,则表明这是一个名词。方法名为名词的方法有返回值。如果不包含这些后缀,则很可能这是一个动词。以动词命名的方法会对某块引用的内存进行一些操作。即所谓的"修改某个值"。下面是几个符合名词/动词命名规则的方法

customArray.enumerate()
customArray.enumerated()
customArray.reverse()
customArray.reversed()
customArray.sort() // changed from .sortInPlace()
customArray.sorted()

下面是一些使用这些方法的代码片段:

var ages = [21, 10, 2] // 变量,不是常量,这样你才能修改它
ages.sort() // 修改值,现在值变成了 [2, 10, 21]
for (index, age) in ages.enumerated() { // "-ed" 是名词,表示会返回一个 ages 拷贝
print("\(index). \(age)") // 打印:1. 2 \n 2. 10 \n 3. 21
}

第一个参数的 label
在函数或方法中的第一个参数现在必须有一个 label ,除非你显式地声明不要。以前,我们调用一个函数或方法时,可以忽略第一个参数的 label

// 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"、"to"、"with"、"in"作为外部参数名。这是为了增加代码的可读性。

如果这个方法不使用介词也不使用 label,你应该在方法定义时,显式地在第一个参数名之前加一个下划线:

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { ... }
override func didMoveToView(_ view: SKView) { ... }

在许多编程语言中,许多方法可以共用一个方法名,但参数名不同。Swift 也不例外,现在,你可以重载方法,APIs 能够将直接将它们转换成合适的调用。下面是一个例子,展示了 index() 方法的两种重载形式:

let names = ["Anna", "Barbara"]
if let annaIndex = names.index(of: "Anna") {
print("Barbara's position: \(names.index(after: annaIndex))")
}

函数类型
函数在声明和调用时,都需要用括号将参数括住:

func f(a: Int) { ... }

f(5)

但是,当你用函数类型作为参数时,你可能会写出这样的代码:

func g(a: Int -> Int) -> Int -> Int  { ... } 
// old way, Swift 2

你会发现代码很难读懂。参数在哪里结束,返回值从哪里开始?在 Swift 3 中,正确的定义方法是

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

Why all this change?

It's easy to read these changes, some of which are tiny but introduce massive breakage, and imagine that Apple's Swift engineers are just out to make our lives harder. However, the truth is that they are working hard to make sure Swift is as easy to learn, easy to use, and fast as possible, which are three very different priorities.
In particular, I have been struck by how committed the Apple team are to ensuring their changes are discussed and agreed in the open, as part of the Swift Evolution community effort. Every change above went through extensive community discussion before being agreed for Swift 3.0, which is an incredible thing to behold.
You can get involved and help shape these changes going forward: they are keen to hear ideas from a wide range of users, and it means the future of Swift really is in your hands.

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,686评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,668评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,160评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,736评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,847评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,043评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,129评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,872评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,318评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,645评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,777评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,470评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,126评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,861评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,095评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,589评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,687评论 2 351

推荐阅读更多精彩内容

  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,066评论 4 62
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,637评论 18 139
  • 对大家来说,你的离去很突然。仅仅是一个中风,半个月,就这样走了。我们曾经努力地想尽办法,连我的中医老师都答应去医院...
    玄月之佑阅读 227评论 0 2
  • 今年的中秋不同往年,月亮是十七才圆,然而人间未必都是团圆的,就像苏东坡说的:人有悲欢离合,月有阴晴圆缺,此事古难全...
    三三小姐阅读 253评论 0 0
  • 最近一则川大的“玻璃杯”事件闹得沸沸扬扬。 围观了整场事件的吃瓜群众表示完全是懵逼的,这,玻璃杯也能出CP了?!!...
    Maggie的小家阅读 312评论 0 0