有一段時(shí)間沒有寫 Swift 了, 前段時(shí)間打算在工程中使用 Swift, 結(jié)果發(fā)現(xiàn)各種東西都變了, 由于點(diǎn)比較分散, 而且官方文檔沒有給出具體例子, 只是羅列了修改點(diǎn), 有些點(diǎn)還不太好理解, 所以自己整理了一下變化, 主要是2.1-3.1的修改, 后續(xù)的更新應(yīng)該也會(huì)繼續(xù)往下面添加, 不過排版的形式還在考慮是最新的排最上面還是最下面...
有必要舉出例子的都會(huì)盡量舉出的例子, 其它的個(gè)人覺得沒什么特別的就會(huì)翻譯略過, 具體還是要參考官網(wǎng)的 Revision History. 如有疑問或者錯(cuò)漏, 希望留言, 大家一起交流.
Swift 2.2更新
*增加了條件編譯塊的內(nèi)容
相當(dāng)于增加了 C 語言里面的條件編譯宏, 這部分內(nèi)容在后續(xù)的版本中還有增強(qiáng), #if, #elseif, #else, #endif都和之前沒有太大的變化, 主要還是條件有比較多的修改, 可以支持 os 類型和版本, arch, 后續(xù)還增加了 Swift 的版本.
*在指定成員描述(Explicit Member Expression)小節(jié)中, 增加了僅僅通過名字和參數(shù)來區(qū)分方法/構(gòu)造器的內(nèi)容
標(biāo)題比較難理解, 其實(shí)就是在2.2中判定方法重名的機(jī)制變了, 直接看例子:
class SomeClass {
func someMethod(x: Int, y: Int) {}
func someMethod(x: Int, z: Int) {}
func overloadedMethod(x: Int, y: Int) {}
func overloadedMethod(x: Int, y: Bool) {}
}
let instance = SomeClass()
let a = instance.someMethod // 無法確定
let b = instance.someMethod(x:y:) // 可以確定
let d = instance.overloadedMethod // 無法確定
let d = instance.overloadedMethod(x:y:) // 依然無法確定
let d: (Int, Bool) -> Void = instance.overloadedMethod(x:y:) // 可以確定
可以看到, 參數(shù)名也需要一致了, 如果參數(shù)名一致, 但是類型不一致則需要顯式寫上方法的類型.
*增加了#selector的形式獲取 selector
之前的版本都是用字符串來尋找 selector, 沒有提示, 很容易出錯(cuò), 而且不報(bào)錯(cuò), 比較坑爹, 2.2增加了用#selector尋找 selector
*在關(guān)聯(lián)類型和協(xié)議關(guān)聯(lián)類型小節(jié)中更新了用 associatedtype 來關(guān)聯(lián)類型的內(nèi)容
// 2.2 以前
protocol Container {
typealias ItemType // <-- 之前為 typealias
mutating func append(item: ItemType)
var count: Int { get }
subscript(i: Int) -> ItemType { get }
}
// 2.2
protocol Container {
associatedtype Item // <-- 修改為 associatedtype
mutating func append(_ item: Item)
var count: Int { get }
subscript(i: Int) -> Item { get }
}
*更新了構(gòu)造失敗小節(jié)中構(gòu)造器在實(shí)例完全構(gòu)造好之前返回 nil 的內(nèi)容
仔細(xì)看了一下文檔中給出的例子, 沒有發(fā)現(xiàn)明顯的區(qū)別, 所以具體也不知道更新了哪里...
*在比較操作符小節(jié)中增加了元組的對(duì)比
元組的對(duì)比需要兩邊里面的類型是一致, 否則會(huì)報(bào)錯(cuò). 直接看官方的例子吧
(1, "zebra") < (2, "apple") // true, 因?yàn)?<2, 后續(xù)的就不會(huì)比了
(3, "apple") < (3, "bird") // true, 因?yàn)?==3, apple<bird
(4, "dog") == (4, "dog") // true
(1,2) < ("aa", "bb") // error
*在關(guān)鍵字和標(biāo)點(diǎn)小節(jié)中,增加了使用關(guān)鍵字作為外部參數(shù)名的內(nèi)容
也就是說現(xiàn)在關(guān)鍵字作為參數(shù)的標(biāo)簽也是可以的了. 如:
func keywordFunc(func x: Int, while y: String){}
*在聲明屬性小節(jié)中更新了關(guān)于 @objc 屬性的內(nèi)容, 現(xiàn)在枚舉和它的 case 都可以使用這個(gè)屬性了
這里增加了一大段描述, 大概就是現(xiàn)在可以給枚舉加 @objc 屬性了, 然后如果要在 Objc 代碼里面使用的話, 類型會(huì)自動(dòng)拼接為 {TYPE}{CASE}, 如:
// xxx.swift
@objc public enum SomeType: Int {
case Custom
case System
case TypeOne
case None
}
// xxx.m
SomeType type = SomeTypeCustom;
對(duì) case 使用 @objc 沒有做多余的闡述, 應(yīng)該和 class 的屬性用是一致的效果.
*更新了操作符小節(jié)中, 關(guān)于自定義操作符中包含點(diǎn)的內(nèi)容
現(xiàn)在可以定義一個(gè)以點(diǎn)(.)開頭的操作符, 例如: 可以定義.+.操作符, 它會(huì)被當(dāng)做一個(gè)獨(dú)立的操作符. 如果一個(gè)自定義操作符不是以.開頭的, 那么它也不能在后續(xù)中包含., 例如+.+會(huì)被當(dāng)做是+后面跟著一個(gè).+操作符
PS: 個(gè)人不太建議定義這種奇奇怪怪的操作符, 如果不能一眼看出其作用或者符合一般的認(rèn)知習(xí)慣, 就會(huì)變成定義了一個(gè)函數(shù)叫 a 一樣無法理解.
*還是在重新拋出函數(shù)和方法小節(jié)中, 增加了重新拋出函數(shù)不能直接拋出錯(cuò)誤
也就是說標(biāo)記為rethrows的函數(shù)不能直接 throw 一個(gè)錯(cuò)誤, 必須要在 do-catch 中拋出, 如:
func someFunction(callback: () throws -> Void) rethrows {
do {
} catch {
throw AnotherError.error
}
}
*在屬性監(jiān)聽小節(jié)中, 增加了傳入 in-out 參數(shù)的時(shí)候, 觸發(fā)屬性監(jiān)聽的內(nèi)容
我覺得這算是之前的一個(gè)小bug, 老版本在傳入屬性作為 in-out 參數(shù)的時(shí)候并不會(huì)調(diào)用 willSet 和 didSet, 3.0解決了這個(gè)問題:
class Test {
var num = 1 {
didSet{
print("will set")
}
willSet{
print("did set")
}
}
}
func testInout( param x : inout Int ){
x = 2
}
var test = Test()
testInout(param: &test.num)
*在 A Swift Tour中增加了錯(cuò)誤處理
在Swift 簡(jiǎn)介中增加了錯(cuò)誤處理的小節(jié)
*更新了弱引用的圖標(biāo), 使得析構(gòu)過程更加清晰
*移除了 C 風(fēng)格的 for 循環(huán), 前++, 后++和前--, 后--都被移除了
*移除了可變函數(shù)參數(shù)和柯里化函數(shù)的特殊語法
Swift 3.0 變動(dòng)
// 2017.1.7增加
* GCD 的修改
GCD 在 Swift 3中得到了徹底的修改, 新語法更適合 Swift 的寫法. 例如:
DispatchQueue.global().async {
// do something in global queue
}
DispatchQueue.main.async {
// do something in main queue
}
具體 GCD 使用細(xì)節(jié)可以看看WWDC 視頻或者官方文檔
*更新了函數(shù)章節(jié)的內(nèi)容, 函數(shù)聲明小節(jié)中所有的參數(shù)都會(huì)默認(rèn)獲得一個(gè)參數(shù)標(biāo)簽了.
以下列代碼為例:
// 函數(shù)聲明未變
func someFunction(firstParameterName: Int, secondParameterName: Int) {
}
// 3.0前版本調(diào)用
someFunction(1, secondParameterName: 2)
// 3.0版本調(diào)用
someFunction(firstParameterName: 1, secondParameterName: 2)
*更新了高級(jí)操作符章節(jié)內(nèi)容, 現(xiàn)在可以把自定義的操作符作為類型方法來定義了, 而不是之前的全局函數(shù).
高級(jí)操作符之前沒有在系列文章中體現(xiàn), 所以暫時(shí)不好對(duì)比了, 如果可能的話我把以前的文檔找出來對(duì)比一下. 總之, 看起來現(xiàn)在友好很多, 以前看 swift 的源碼的時(shí)候會(huì)發(fā)現(xiàn)一大堆的操作符定義...
*在訪問控制章節(jié)中增加了對(duì) open 和 fileprivate 的解釋.
也就是說訪問控制又增加了2個(gè)級(jí)別, 之前 private 對(duì)應(yīng)了現(xiàn)在的 fileprivate, 列一個(gè)列表來說明變化吧:
| 修飾符 | 3.0以前版本 | 3.0版本 |
|---|---|---|
| open | 無 | 與 public 一樣, 可以被外部引用 |
| public | 跨模塊可見 | 跨模塊可見 |
| internal | 模塊內(nèi)部的任何源文件可見 | 模塊內(nèi)部的任何源文件可見 |
| private | 同一個(gè)源文件內(nèi)可見 | 當(dāng)前類型可見 |
| fileprivate | 無 | 同一個(gè)源文件內(nèi)可見 |
在3.0中 open 相比較于 public 的區(qū)別如下:
1. open 僅可用于類以及類的成員變量
2. 用 public 或者更嚴(yán)格的訪問級(jí)別定義的類, 只能在當(dāng)前模塊(定義該類的模塊)被繼承
3. 用 public 或者更嚴(yán)格的訪問級(jí)別定義的類成員變量, 只能在當(dāng)前模塊被重載
4. 用 open 定義的類既可以在當(dāng)前模塊繼承, 也可以在任意引入該模塊的地方繼承
5. 用 open 定義的類成員變量既可以在當(dāng)前模塊重載, 也可以在任意引入該模塊的地方重載
上述的幾點(diǎn)變化都設(shè)計(jì)到繼承, 重載, 所以 open 僅可用于類和類的成員變量.
*函數(shù)中 inout 修飾符的位置發(fā)生了變化
// 3.0前
func swapTwoInts(inout a: Int, inout _ b: Int) {
let t = a
a = b
b = t
}
var a = 1, b = 2
swapTwoInts(&a, &b) // &去掉會(huì)報(bào)錯(cuò)
// 3.0
var x = 10
func f(a: inout Int, b: inout Int) {
a += 1
b += 10
}
f(a: &x, b: &x) // Invalid, in-out arguments alias each other
*更新了逃逸閉包和自動(dòng)閉包章節(jié)的 @noescape 和 @autoclosure 的信息, 目前它們是類型信息, 而不是聲明屬性了.
@noescape被去除, 增加了正向表意的 @escaping, 位置也有所變化.
// 3.0以前
var completionHandlers: [() -> Void] = [] // 存儲(chǔ)閉包用
func someFunctionWithNoescapeClosure(@noescape closure: () -> Void) {
closure()
completionHandlers.append(closure) // error
}
func someFunctionWithEscapingClosure(completionHandler: () -> Void) {
completionHandlers.append(completionHandler)
}
// 3.0
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
completionHandlers.append(completionHandler)
}
@autoclosure沒有更名, 只是和 @escaping 一樣變了位置
// 3.0以前
func serveCustomer(@autoclosure customerProvider: () -> String) {
print("Now serving \(customerProvider())!")
}
serveCustomer(customersInLine.removeAtIndex(0))
// 3.0
func serve(customer customerProvider: @autoclosure () -> String) {
print("Now serving \(customerProvider())!")
}
serve(customer: customersInLine.remove(at: 0))
*高級(jí)操作符章節(jié)增加了自定義 infix 操作符優(yōu)先級(jí)組的信息
直接看文檔吧, 目前不打算深入了解, 看文檔
*一系列更新, 包括用 macOS 取代 OS X, Error 替代 ErrorProtocol, 諸如ExpressibleByStringLiteral的協(xié)議改名為StringLiteralConvertible.
*更新了泛型章節(jié)的 where語句中的泛型小節(jié), 現(xiàn)在 where 語句被寫在了聲明的最后邊
直接看代碼對(duì)比來看where語句的變化吧
// 3.0以前
func allItemsMatch<
C1: Container, C2: Container // <-- 類型約束, 必須實(shí)現(xiàn)Container
where C1.ItemType == C2.ItemType, C1.ItemType: Equatable> // <-- 協(xié)議內(nèi)部關(guān)聯(lián)類型必須相等, 關(guān)聯(lián)類型必須實(shí)現(xiàn)Equatable協(xié)議
(someContainer: C1, _ anotherContainer: C2) -> Bool {
// do something
}
// 3.0
func allItemsMatch<
C1: Container, C2: Container>
(_ someContainer: C1, _ anotherContainer: C2) -> Bool
// where 語句的位置發(fā)成了變化, 被放在了尖括號(hào)外部
where C1.ItemType == C2.ItemType, C1.ItemType: Equatable {
// do something
}
*更新了逃逸閉包的內(nèi)容, 現(xiàn)在它默認(rèn)是非逃逸閉包了
參考上面的變化
*更新了基礎(chǔ)章節(jié)中的 optional 綁定以及語句章節(jié)中 while 語句的內(nèi)容, 現(xiàn)在 if, while 和 guard 語句用一個(gè)逗號(hào)分割的列表來替代了 where 語句, 例如:
// 3.0以前
if let firstNumber = Int("4") {
if let secondNumber = Int("42") {
if firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
}
}
// Prints "4 < 42 < 100"
// 3.0
if let firstNumber = Int("4"), let secondNumber = Int("42"), firstNumber < secondNumber && secondNumber < 100 {
print("\(firstNumber) < \(secondNumber) < 100")
}
// Prints "4 < 42 < 100"
*在流程控制中的 switch 中的 case 中添加了多種模式匹配.
其實(shí)就是說一個(gè)case分支現(xiàn)在可以寫多個(gè)模式匹配了, 如果用原來的寫法的話, 就應(yīng)該要用 fallthrough來寫2個(gè) case.
switch control expression {
case pattern 1:
statements
case pattern 2 where condition:
statements
case pattern 3 where condition, <-- 這里
pattern 4 where condition:
statements
default:
statements
}
*更新了關(guān)于函數(shù)類型的內(nèi)容, 現(xiàn)在函數(shù)參數(shù)標(biāo)簽不再屬于函數(shù)類型的一部分了
直接看看官方的例子:
func someFunction(left: Int, right: Int) {}
func anotherFunction(left: Int, right: Int) {}
func functionWithDifferentLabels(top: Int, bottom: Int) {}
var f = someFunction // 現(xiàn)在 f 的類型是 (Int, Int) -> Void, 而不是 (left: Int, right: Int) -> Void 了.
f = anotherFunction // OK
f = functionWithDifferentLabels // OK
func functionWithDifferentArgumentTypes(left: Int, right: String) {}
func functionWithDifferentNumberOfArguments(left: Int, right: Int, top: Int) {}
f = functionWithDifferentArgumentTypes // Error
f = functionWithDifferentNumberOfArguments // Error
*在協(xié)議章節(jié)更新了協(xié)議組合的內(nèi)容, 以及類型章節(jié)中協(xié)議組合使用了 Protocol1 & Protocol2的新用法
// 3.0以前
protocol Named {
var name: String { get }
}
protocol Aged {
var age: Int { get }
}
struct Person: Named, Aged {
var name: String
var age: Int
}
func wishHappyBirthday(celebrator: protocol<Named, Aged>) { // <-- 區(qū)別
print("Happy birthday \(celebrator.name) - you're \(celebrator.age)!")
}
let birthdayPerson = Person(name: "Malcolm", age: 21)
wishHappyBirthday(birthdayPerson)
// 3.0
protocol Named {
var name: String { get }
}
protocol Aged {
var age: Int { get }
}
struct Person: Named, Aged {
var name: String
var age: Int
}
func wishHappyBirthday(to celebrator: Named & Aged) { // <-- 區(qū)別
print("Happy birthday, \(celebrator.name), you're \(celebrator.age)!")
}
let birthdayPerson = Person(name: "Malcolm", age: 21)
wishHappyBirthday(to: birthdayPerson)
*在動(dòng)態(tài)類型描述的內(nèi)容, 現(xiàn)在使用新的 type(of:)語法來獲取動(dòng)態(tài)類型描述
typeof 的用法官方給了例子, 其實(shí)也就是相當(dāng)于給了個(gè)全局的函數(shù), 返回一個(gè) Class 對(duì)象.
class SomeBaseClass {
class func printClassName() {
print("SomeBaseClass")
}
}
class SomeSubClass: SomeBaseClass {
override class func printClassName() {
print("SomeSubClass")
}
}
let someInstance: SomeBaseClass = SomeSubClass()
// someInstance 在編譯期的時(shí)候有一個(gè)靜態(tài)的類型-- SomeBaseClass, 在 runtime 的時(shí)候有一個(gè)動(dòng)態(tài)的類型--SomeSubClass
type(of: someInstance).printClassName()
// 打印出"SomeSubClass"
*更新了航控制語句小節(jié)中使用#sourceLocation(file:line:)語法的內(nèi)容
根據(jù)描述應(yīng)該是可以自己制定代碼的文件名和行數(shù), 一般作為診斷和 debug 來使用.
*更新了函數(shù)永不返回中使用新的 Never 類型
swift 定義了一種 Never 的類型, 它指示了函數(shù)或者方法不會(huì)返回到調(diào)用方
*更新了 In-Out 參數(shù)小節(jié)中的內(nèi)容--只有非逃逸閉包可以捕獲 in-out 參數(shù)
*更新了默認(rèn)參數(shù)值小節(jié)中關(guān)于默認(rèn)參數(shù)的內(nèi)容, 現(xiàn)在他們不能在函數(shù)調(diào)用中重新訂閱了
*更新了屬性章節(jié)中屬性參數(shù)使用冒號(hào)
主要是配合 @available來使用, 如下面的例子, @available后面接 typealias(只作用一個(gè), 有多個(gè) typealias 只會(huì)作用于下面第一個(gè)) 導(dǎo)致 MyProtocol在后續(xù)發(fā)布后并不能真正地 alias 為MyRenamedProtocol, 只是為編譯器提供了提示的信息, 報(bào)錯(cuò)會(huì)有 fix-it 出現(xiàn).
// 第一次版本發(fā)布
protocol MyProtocol {
// protocol definition
}
// 后續(xù)發(fā)布版本重新命名了MyProtocol
protocol MyRenamedProtocol {
// protocol definition
}
@available(*, unavailable, renamed: "MyRenamedProtocol")
typealias MyProtocol = MyRenamedProtocol
enum SomeEnum: MyProtocol { // <-- 這里報(bào)錯(cuò), 并出現(xiàn) fix-it, 要求變?yōu)镸yRenamedProtocol,
//如果MyRenamedProtocol拼寫錯(cuò)誤如寫成MyRenamedProtocolTest, fix-it 的結(jié)果也會(huì)編程MyRenamedProtocolTest
}
*在重新拋出函數(shù)和方法小節(jié)中增加了關(guān)于在 rethrowing 函數(shù)的catch block內(nèi)部錯(cuò)誤的內(nèi)容.
直白的說, 增加了在標(biāo)注為 rethrows 的函數(shù)/方法中, 只有出現(xiàn)一個(gè)異常語句, 基本可以理解為只能出現(xiàn)一個(gè) try.
enum SomeError:Error {
case error
}
enum AnotherError:Error {
case error
}
func alwaysThrows() throws {
throw SomeError.error
}
func someFunction(callback: () throws -> Void) rethrows {
do {
try callback()
// try alwaysThrows() // 去掉注釋就報(bào)錯(cuò)
} catch SomeError.error{
throw AnotherError.error
}catch AnotherError.error{
}
}
*增加了#selector 的objc屬性的 getter 和 setter 方法描述.
之前的版本都是用字符串來尋找 selector, 沒有提示, 很容易出錯(cuò), 而且不報(bào)錯(cuò), 比較坑爹, 3.0增加了類似原來@selector 的形式, 而且更加好用了.
class SomeClass: NSObject {
let property: String
@objc(doSomethingWithInt:)
func doSomething(_ x: Int) {}
init(property: String) {
self.property = property
}
}
let selectorForMethod = #selector(SomeClass.doSomething(_:))
let selectorForPropertyGetter = #selector(getter: SomeClass.property)
*增加了類型別名聲明小節(jié)中, 關(guān)于泛型的別名和在協(xié)議中使用別名的內(nèi)容
類型別名可以使用泛型參數(shù)來給定一個(gè)已有的泛型起名,例如:
typealias StringDictionary<Value> = Dictionary<String, Value>
// 下面兩個(gè) dictionary 都是一樣的類型
var dictionary1: StringDictionary<Int> = [:]
var dictionary2: Dictionary<String, Int> = [:]
類型別名用泛型參數(shù)聲明了時(shí)候, 參數(shù)是可以加限制的, 例如:
typealias DictionaryOfInts<Key: Hashable> = Dictionary<Key, Int>
在協(xié)議內(nèi)部, 類型別名可以提供一個(gè)更加簡(jiǎn)短和方便的名字, 例如:
protocol Sequence {
associatedtype Iterator: IteratorProtocol
typealias Element = Iterator.Element
}
func sum<T: Sequence>(_ sequence: T) -> Int where T.Element == Int {
// ...
}
*更新了函數(shù)類型小節(jié)的內(nèi)容, 現(xiàn)在參數(shù)的圓括號(hào)是必須的了
主要是因?yàn)樵M的原因, ((Int, Int)) -> Void和(Int, Int) -> Void還是有很明顯的區(qū)別的.
*更新了屬性章節(jié)中, @IBAction, @IBOutlet 和 @NSManaged會(huì)附帶@objc的內(nèi)容
也就是說只要加上了上面三種屬性的其中之一, 就會(huì)自動(dòng)加上 @objc屬性.
*在屬性章節(jié)中, 增加了 @GKInspectable 的內(nèi)容
文檔的描述如下:
Apply this attribute to expose a custom GameplayKit component property to the SpriteKit editor UI.
應(yīng)用此屬性來暴露一個(gè)自定義的 GameplayKit 組件屬性到 SpriteKit 編輯器的 UI 上
說實(shí)話, 沒有玩過 GameplayKit, 只能硬翻了 :p, 字面上的意思也還好理解 GK=gamekit, inspectable, 可檢測(cè)到的
*更新了可選協(xié)議要求小節(jié)的內(nèi)容, 使得這部分代碼只用于 objc 變得更加清晰了
// 3.0以前
@objc protocol CounterDataSource {
optional func incrementForCount(count: Int) -> Int
optional var fixedIncrement: Int { get }
}
// 3.0
@objc protocol CounterDataSource {
@objc optional func increment(forCount count: Int) -> Int
@objc optional var fixedIncrement: Int { get }
}
*移除了函數(shù)聲明小節(jié)中, 在函數(shù)參數(shù)中顯式使用 let 的內(nèi)容
以前記得是如果整個(gè)函數(shù)沒有對(duì)參數(shù)進(jìn)行修改, 就要在參數(shù)中加上 let 來修飾, 看起來這個(gè)設(shè)定被丟棄了.
*移除了語句章節(jié)中, Boolean 協(xié)議的內(nèi)容, 現(xiàn)在這個(gè)協(xié)議已經(jīng)從 Swift 標(biāo)準(zhǔn)庫中移除了
*糾正了聲明屬性小節(jié)中對(duì) @NSApplicationMain的描述
Swift 3.0.1 變動(dòng)
*更新了 ARC 章節(jié)中, weak 和 unowned 引用的內(nèi)容
weak和 unowned 因?yàn)橐呀?jīng)找不到2.2的描述, 看了最新的描述, 和之前的理解沒有明顯的差距, 貌似都是增加了一個(gè) NOTE,
weak 的 NOTE 是:
Property observers aren’t called when ARC sets a weak reference to nil.
weak 屬性被自動(dòng)設(shè)置為 nil 的時(shí)候不會(huì)觸發(fā)屬性觀察方法
之前自動(dòng)設(shè)置為 nil 的時(shí)候是會(huì)觸發(fā)屬性監(jiān)聽的, 新版本改為不觸發(fā)了.
小 Tip: 如果要驗(yàn)證老的邏輯, 可以在Build Settings里面Use Legacy Swift Language Version 設(shè)置為 Yes
unowned 的 NOTE 是:
The examples above show how to use safe unowned references. Swift also provides unsafe unowned references for cases where you need to disable runtime safety checks—for example, for performance reasons. As with all unsafe operations, you take on the responsiblity for checking that code for safety.
You indicate an unsafe unowned reference by writing unowned(unsafe). If you try to access an unsafe unowned reference after the instance that it refers to is deallocated, your program will try to access the memory location where the instance used to be, which is an unsafe operation.
上面的例子展示了如何安全地使用 unowned 引用. Swift 還提供了非安全的 unowned 引用, 來應(yīng)付不需要在 runtime 時(shí)期做安全性檢查的場(chǎng)景, 例如為了提高性能. 如其它的非安全操作, 你需要自己為代碼安全性負(fù)責(zé).
用unowned(unsafe)來標(biāo)記非安全的 unowned 引用. 如果你嘗試訪問一個(gè)非安全引用的實(shí)例, 而且它已經(jīng)被析構(gòu)了, 進(jìn)程會(huì)訪問這個(gè)實(shí)例之前存在的內(nèi)存空間, 這是個(gè)不安全的操作.
這個(gè) NOTE 說明 Swift 提供了一種新的, 高性能的引用方式, 只是要付出安全性的代價(jià).
*在聲明修飾符章節(jié)中增加了unowned, unowned(safe), 和 unowned(unsafe)的說明
上面已經(jīng)有部分說明了
unowned(safe)是unowned的顯式寫法, 也就是說, unowned 默認(rèn)就是unowned(safe).
unowned(unsafe) 與unowned(safe)的區(qū)別主要是, unowned(safe)在訪問一個(gè)已經(jīng)析構(gòu)的對(duì)象, 會(huì)直接觸發(fā) runtime error, 而unowned(unsafe) 則會(huì)去訪問這個(gè)實(shí)例曾經(jīng)存在的地址, 其作用則是未知的.
*在Any 和 AnyObject 類型轉(zhuǎn)換小節(jié)中增加了關(guān)于當(dāng)值是被期望是 Any 的時(shí)候使用 optional 的小記
The Any type represents values of any type, including optional types. Swift gives you a warning if you use an optional value where a value of type Any is expected. If you really do need to use an optional value as an Any value, you can use the as operator to explicitly cast the optional to Any, as shown below.
let optionalNumber: Int? = 3
things.append(optionalNumber) // Warning
things.append(optionalNumber as Any) // No warning
Any 類型帶了了所有的類型, 包括 Optional 類型. 當(dāng)你在需要 Any 類型的場(chǎng)合使用了 Optional 類型, 編譯器會(huì)給你一個(gè)警告. 如果你確實(shí)需要把 Optional 的值當(dāng)做 Any 類型使用, 可以用
as操作符把它顯式轉(zhuǎn)化為Any, 如代碼所示.
*在 Expressions 章節(jié)中拆分了圓括號(hào)表述和元組表述
Swift 3.1 變動(dòng)
*增加了包含 Where 從句泛型的拓展小節(jié)
現(xiàn)在拓展中的泛型也可以加 where 從句了, 來限定拓展的內(nèi)容:
extension Stack where Element: Equatable {
func isTop(_ item: Element) -> Bool {
guard let topItem = items.last else {
return false
}
return topItem == item
}
}
如果Stack 指定了沒有實(shí)現(xiàn)Equatable的類型, 在使用 isTop 的時(shí)候會(huì)報(bào)錯(cuò).
struct NotEquatable { }
var notEquatableStack = Stack<NotEquatable>()
let notEquatableValue = NotEquatable()
notEquatableStack.push(notEquatableValue)
notEquatableStack.isTop(notEquatableValue) // Error
*增加了聲明屬性小節(jié)中關(guān)于 Swift 版本的available屬性的內(nèi)容
針對(duì) Swift 版本也可以使用 @available 了, 之前都是平臺(tái)和系統(tǒng)版本之類的.
@available(swift version-number)
*更新了條件編譯塊小節(jié)中 Swift 版本數(shù)字的內(nèi)容, 現(xiàn)在patch 版本號(hào)也允許使用了
可以理解為之前的條件編譯也加上了 Swift 版本的控制.
*更新了函數(shù)類型小節(jié)的內(nèi)容. 現(xiàn)在 Swift 區(qū)分多參數(shù)函數(shù)和只有一個(gè)元組類型參數(shù)的函數(shù)了
直接上例子吧:
// 3.1以前:
func methodForTuple(t:(a: Int, b: Int, c: Int)){}
func methodForMulti(a: Int, b : Int, c: Int){}
var tupleFunction = methodForTuple
tupleFunction = methodForMulti // 沒有報(bào)錯(cuò), 說明編譯器認(rèn)為這兩個(gè)個(gè)函數(shù)是一個(gè)類型的
// 3.1之后就會(huì)報(bào)錯(cuò)了, 因?yàn)闀簳r(shí)沒有更新 Xcode到最新版, 所以沒有驗(yàn)證這一點(diǎn)