【讀書筆記】The Swift Programming Language (Swift 4.0.3)

iOS122發表於2018-01-06

素材:Language Guide

初次接觸 Swift,建議先看下 A Swift Tour,否則思維轉換會很費力,容易卡死或鑽牛角尖。

同樣是每一章只總結3個自己認為最重要的點。這樣挺好!強迫你去思考去取捨。以後再看,也方便快速重建記憶。

注意: 個人筆記,僅供參考,不保證嚴格意義上的正確性。

The Basics

* 整數,優先使用 Int,浮點數,優先使用 Double
* 可以使用 0b 表示二進位制,可以在數字中間插入可讀字元 _,如 182_3880_25
* as 僅用於相容型別間的相互轉換.非相容型別的轉換,由各個類自己的初始化方法實現.

Basic Operators

* 空格對操作符的影響很大,如 a??b 應該寫作 a ?? b, 因為 a? 也是一個有效的操作符.
* a ?? b 返回的是 a unwrap 後的值或 b 的值. ?? 比 js 的 || 好使多了,因為前者能準確區分零值和nil值.只有nil值時,才需要使用預設值.
* names[0..<2] 本質上,是得到了一個陣列. ==> 本質上,應該是 array 的[]操作符,過載後,支援了 range 引數.

Strings and Characters

* 多行字串的起始偏移,是根據末尾的 """ 的偏移 來判定的.
* collection 型別,都有自己的 index struct.String 中涉及的增刪改查操作,適用於所有 collection 型別.
* SubString 的增刪改查,只是一個原有 String 上的遊標操作.

Collection Types

* collection type 是struct,是複製傳值,即使只是 a = b
* 操作符過載之後,可以支援陣列相加(+)等操作,可以顯著程式碼的可讀性和簡潔性
* 能在編譯器推匯出的模板型別部分,都可以省略例項型別部分

Control Flow

* switch case 匹配中的 range,也支援源於 String.index 的range
* where 充當一個查詢子句的角色
* #available的確可以讓API可用性檢查,更方便.

Functions

* 可變字串的 label 是可以在函式宣告時,由自己指定的. ==> 可變引數,不需要是最後一組引數
* inout 有點像是指標傳值;不同的是,在函式內使用時,不需要處理指標解引用操作,直接一個普通 var 變數使用即可.
* 引數預設是 let 不可變型別,不允許修改

Closures

* function type 不包含 label 部分 --> 傳遞function時,其label部分會被自動忽略. -->  在絕大部分場景中,二者是相容的.
* closure 可以省略引數型別,是因為型別推導機制的存在 --> 尾閉包,可以省略 ();
* 用作函式引數的閉包,如果想在函式外使用,需要額外加 @escaping 標記 ;@autoclosure 會自動補全用作函式引數的閉包的{}符號 --> @autoclosure 標記的閉包,是有可能和其他一般引數標記的引數,函式簽名重複的.

Enumerations

* 遞迴定義的列舉,就是一個演示函數語言程式設計的絕佳示例.
* swift 中的列舉,變成了一中,可以有效承載資料和演算法的描述性資料結構.
* swift 中的 enumeration ,極有可能成為一種新的 Model 載體.

Classes and Structures

* 可選變數,的確會被自動初始化為 nil.
* swift 中,可以設定元件的 frame 了.呼哈哈 label.frame.origin.x = 100.
* String, Array, and Dictionary 竟然是在swift中被實現為結構體了,值傳遞.

Properties

* lazy 關鍵字實現的屬性懶載入,果然比重寫 getter 方法,要清晰簡潔好多啊.
* 可以用 static 或 class 宣告類變數/類方法; 用class 宣告的類變數或類方法,支援子類重寫其實現.
* [self class] 等價寫法是: type(of: self).

Methods

* 結構體例項中,方法是否能夠修改屬性,也受例項本身的可變性的影響.
* 結構體或列舉等值型別,允許在例項方法內,直接給 self 賦值,完整替換.
* 列舉型別的相關操作,都可以封裝在列舉型別自身,這樣封裝性會更好.

Subscripts

* subscript 是一個新的語言特性,不是簡單的函式重寫.
* subscript 可以接收多個引數
* subscript 的引數和返回值,可以完全自定義

Inheritance

* 可以通過 super 來使用父類方法或屬性.
* 可以在方法或屬性前加 final 關鍵字,來禁止被子類重寫.
* 可以在類前加 final 關鍵字,來禁止被繼承.

Initialization

* deisingnated init 一般只呼叫父類 deisingnated init; convenience init 一般只呼叫同類的 desingnated init;deisingnated init 中,是不允許呼叫同級的另一個deisingnated init;子類中,只允許呼叫父類的 designated init.
* 呼叫父類初始化方法前,子類自有的 stored property 必須先全部初始化 --> super.init 如果不顯式呼叫, 系統會自動呼叫. 在呼叫 super.init 之前,不能呼叫任何例項方法,因為物件還沒有效初始化.
* 用 closure 指定預設值和屬性的get/set 方法的區別在於 宣告有個等號(=),說明前者是個賦值操作.

Deinitialization

* 把變數置為 nil,即可觸發 deinit.
* deinit 執行順序:  子類 --> 父類.
* 不能在子類 deinit 中呼叫 super.deinit.

Optional Chaining

* 在訪問 optional 物件的內部屬性時,必須使用 ? 或 ! 進行 unwrap 操作.
* 賦值操作中,如果左側是要賦值給 optional 例項的某個屬性,則會先 unwrap optional 例項,如果不為nil,才會計算右側的表示式.
* 鏈式語法中,有一個 optional 呼叫(X?),則返回值必然是 optional 的.

Error Handling

* 函式A中,可以 try 函式B,如果函式B丟擲錯誤,則會直接拋給 A 的呼叫者.
* do-catch 中的catch 部分 和 switch-case 中的case部分,匹配方式很像.
* try? 的作用是是將函式返回值轉換為 optional 物件. try? 的返回值,有可能是多層 optional,層數等於原函式返回值的 optional wrap 層數 + 1.try! 是保證不會丟擲異常,如果有,就直接crash.

Type Casting

* is 近似於 isKind; 精確判斷時,可以考慮使用 type(of: T1) == T2.self
* 型別轉換用的是 as? 或 as!,用法習慣和 try? try! 類似.
* 陣列具體化型別宣告為 Any / AnyObject 時,陣列內可同時存放多種型別不相容的例項.

Nested Types

* 支援型別巢狀定義,這已經是很大的突破了.
* 即使在函式內部,也可以定義新的型別.
* 可以用.語法,訪問巢狀定義的型別.

Extensions

* extensions 和 categories 的重要區別之一是,前者不需要寫名字.
* extensions 不允許覆蓋已有方法,且不同 extentsion 中的方法簽名也不允許重複.
* extentsion 擴充套件的東西,是可以被子類繼承的.

Protocols

* 在swift 的設定中, protocol 也屬於 type,可以用於任何 type 適用的場景.
* 在型別宣告遵循某協議以外的位置,書寫符合協議的方法是,用 & 連線多個協議,如 AP&BP&CP.
* protocol 可以在 extension 中定義自己的方法,任意遵循此協議的型別的例項都可以呼叫此協議自己的方法實現. --> 可以在 extension 實現協議規定的屬性或方法的預設實現. -->可以用 extension-where來指定,僅在特定條件下,才有效的protocal自有協議方法.

Generics

* 泛型型別中的佔位型別,也可以用於其自身的 extention 中.
* 可以用類似 <T: SomeClass> 或 <T: SomeAProtocol&SomeBProtocol> 或 where 子句 指定佔位型別本身需要滿足的型別或協議約束. --> 藉助 associatedtype 關鍵字, protocol 也可以支援泛型.
* AnyObject 本身不能直接在型別定義時,宣告應遵循的協議的位置使用 --> 可以先定義一個協議 A,繼承自 AnyObject,然後讓型別定義時宣告遵循協議 A,即可間接使用協議 AnyObject.

Automatic Reference Counting

* optional 變數,也是強引用 -> 可以繼續使用 weak 關鍵字宣告弱引用屬性或變數 -> unowned 與 weak 的區別是,前者不會自動置為 nil.
* closure 是引用型別 -> closure 內引用例項屬性,必須加 self字首 -> closure 的引數宣告前,可以加一個 capture list,如 [unowned self],來解決迴圈引用問題.
* 可以證明,在非 self 以外的情況, closure 並不會引起內部使用變數的引用計數的變化.

Memory Safety

* inout 標記的函式引數,是最容易引起訪問衝突問題的.
* 往同一函式,同時以不同的 inout 引數,傳遞同一個實際變數,會引起訪問衝突 --> 這一行為,可以被自動識別並標記出來
* 型別方法呼叫,不允許使用自身作為 inout 引數傳遞給自己的某個方法.

Access Control

* 預設訪問級別是 internal,可以在定義它的模組內的各個原始檔之間自由使用.
* fileprivate 和 private 並存,是因為swift中允許型別巢狀定義.
* 子類的訪問級別不能比父類更寬鬆;但是子類可以通過重寫機制,使父類的成員的訪問級別變的更寬鬆.

Advanced Operators

* 過載操作符的語法是: static [prefix|infix|postfix] func 某個操作符 --> == 和 != 也可以過載,來簡化等價判斷操作.
* 複合操作符,要單獨過載,不會自動根據已有操作符自動推導,如 不會根據 + ,自動實現 +=.
* 可以基於已有操作符,宣告自己的操作符: prefix|infix|postfix operator 操作符,infix 二元操作符,要單獨宣告優先順序,如 : infix operator +-: AdditionPrecedence.

相關文章