Swift 關鍵字

SwiftGG翻譯組發表於2019-08-22

作者:Jordan Morgan,原文連結,原文日期:2017-02-11 譯者:鄭一一;校對:numbbbbbpmst;定稿:Pancf

有句話之前我提過,今天還想再說一次。那就是打鐵還需自身硬。對於自身能力的嚴格要求,可以幫助實現我們所有夢寐以求的東西。

說起來可能有些消極,知識畢竟是永遠學不完的。不論如何,今天 我們先來學習一下 Swift 中的每一個關鍵字(V3.0.1),在介紹每個關鍵字的時候,同時會附帶一段程式碼加以說明。

在這些關鍵字之中,會有你熟悉或者不熟悉的部分。但為了最好的閱讀和學習體驗,我把它們全部列出來了。文章篇幅有些長,你準備好了麼?

讓我們現在就開始吧。

宣告式關鍵字

associatedtype:在協議中,定義一個型別的佔位符名稱。直到協議被實現,該佔位符才會被指定具體的型別。

protocol Entertainment  
{  
    associatedtype MediaType  
}

class Foo : Entertainment  
{  
    typealias MediaType = String //可以指定任意型別
}
複製程式碼

class:通用、靈活的結構體,是程式的基礎組成部分。與 struct 類似,不同之處在於:

  • 允許一個類繼承另一個類的特性。

  • 型別轉換,允許在執行時檢查和指定一個類的實際型別。

  • 析構方法允許類的例項釋放所有資源。

  • 引用計數允許多個引用指向一個例項。

    class Person
    {
    var name:String
    var age:Int
    var gender:String
    }

deinit:當一個類的例項即將被銷燬時,會呼叫這個方法。

class Person  
{  
    var name:String  
    var age:Int  
    var gender:String

    deinit  
    {  
        //從堆中釋放,並釋放的資源
    }  
}
複製程式碼

enum:定義了包含一組有關聯的值的型別,並可以以一種型別安全的方式使用這些值。在 Swift 中,列舉是一等型別,擁有在其它語言中只有 class 才會支援的特性。

enum Gender  
{  
    case male  
    case female  
}
複製程式碼

extension:允許給已有的類、結構體、列舉、協議型別,新增新功能。

class Person  
{  
    var name:String = ""  
    var age:Int = 0  
    var gender:String = ""  
}

extension Person  
{  
    func printInfo()  
    {  
        print("My name is \(name), I'm \(age) years old and I'm a \(gender).")  
    }  
}
複製程式碼

fileprivate:訪問控制許可權,只允許在定義原始檔中訪問。

class Person  
{  
    fileprivate var jobTitle:String = ""  
}

extension Person  
{
    //當 extension 和 class 在同一個檔案中時,允許訪問
    func printJobTitle()  
    {  
        print("My job is (jobTitle)")  
    }  
}
複製程式碼

func:包含用於執行特定任務的程式碼塊。

func addNumbers(num1:Int, num2:Int) -> Int  
{  
    return num1+num2  
}
複製程式碼

import:引入一個以獨立單元構建的框架或者應用。

import UIKit

//可以使用 UIKit 框架下的所有程式碼
class Foo {}
複製程式碼

init:類、結構體、列舉的例項的初始化準備過程。

class Person
{  
    init()  
    {  
        //設定預設值,例項準備被使用
    }  
}
複製程式碼

inout:將一個值傳入函式,並可以被函式修改,然後將值傳回到呼叫處,來替換初始值。適用於引用型別和值型別。

func dangerousOp(_ error:inout NSError?)  
{  
    error = NSError(domain: "", code: 0, userInfo: ["":""])  
}

var potentialError:NSError?
dangerousOp(&potentialError)

//程式碼執行到這裡,potentialError 不再是 nil,而是已經被初始化
複製程式碼

internal:訪問控制許可權,允許同一個模組下的所有原始檔訪問,如果在不同模組下則不允許訪問。

class Person  
{  
    internal var jobTitle:String = ""  
}

let aPerson = Person()  
aPerson.jobTitle = "This can set anywhere in the application"
複製程式碼

let:定義一個不可變的變數。

let constantString = "This cannot be mutated going forward"
複製程式碼

open:訪問控制許可權,允許在定義的模組外也可以訪問原始檔裡的所有類,並進行子類化。對於類成員,允許在定義的模組之外訪問和重寫。

open var foo:String? //這個屬性允許在 app 內或 app 外重寫和訪問。在開發框架的時候,會應用到這個訪問修飾符。
複製程式碼

operator:特殊符號,用於檢查、修改、組合值。

//一元運算子 "-",改變值的符號
let foo = 5  
let anotherFoo = -foo //anotherFoo 等於 -5

//二元運算子 "+" 將兩個值相加
let box = 5 + 3

//邏輯運算子 "&&" 將兩個布林值進行組合運算
if didPassCheckOne && didPassCheckTwo

//三元運算子需要使用三個值
let isLegalDrinkingAgeInUS:Bool = age >= 21 ? true : false
複製程式碼

private:訪問控制許可權,只允許實體在定義的類以及相同原始檔內的 extension 中訪問。

class Person  
{  
    private var jobTitle:String = ""  
}

// 當 extension 和 class 不在同一個原始檔時
extension Person  
{
    // 無法編譯通過,只有在同一個原始檔下才可以訪問
    func printJobTitle()  
    {  
        print("My job is (jobTitle)")  
    }  
}
複製程式碼

protocol:定義了一組方法、屬性或其它要求,用於滿足特定任務和一系列功能。

protocol Blog  
{  
    var wordCount:Int { get set }  
    func printReaderStats()  
}

class TTIDGPost : Blog  
{  
    var wordCount:Int

    init(wordCount:Int)  
    {  
        self.wordCount = wordCount  
    }

    func printReaderStats()  
    {  
        //列印 post 的資料  
    }  
}
複製程式碼

public:訪問控制許可權,允許在定義的模組外也可以訪問原始檔裡的所有類,但只有在同一個模組內可以進行子類化。對於類成員,允許在同個模組下訪問和重寫。

public var foo:String? //只允許在 app 內重寫和訪問。
複製程式碼

static:用於定義類方法,在型別本身進行呼叫。此外還可以定義靜態成員。

class Person  
{  
    var jobTitle:String?

    static func assignRandomName(_ aPerson:Person)  
    {  
        aPerson.jobTitle = "Some random job"  
    }  
}

let somePerson = Person()  
Person.assignRandomName(somePerson)  
//somePerson.jobTitle 的值是 "Some random job"
複製程式碼

struct:通用、靈活的結構體,是程式的基礎組成部分,並提供了預設初始化方法。與 class 不同,當 struct 在程式碼中被傳遞時,是被拷貝的,並不使用引用計數。除此之外,struct 沒有下面的這些功能:

  • 使用繼承。

  • 執行時的型別轉換。

  • 使用析構方法。

    struct Person
    {
    var name:String
    var age:Int
    var gender:String
    }

subscript:訪問集合、列表、序列中成員元素的快捷方式。

var postMetrics = ["Likes":422, "ReadPercentage":0.58, "Views":3409]  
let postLikes = postMetrics["Likes"]
複製程式碼

typealias:給程式碼中已經存在的類,取別名。

typealias JSONDictionary = [String: AnyObject]

func parseJSON(_ deserializedData:JSONDictionary){}
複製程式碼

var:定義可變變數。

var mutableString = ""  
mutableString = "Mutated"
複製程式碼

語句中的關鍵詞

break:終止程式中迴圈的執行,比如 if 語句、switch 語句。

for idx in 0...3  
{  
    if idx % 2 == 0  
    {  
        //當 idx 等於偶數時,退出 for 迴圈  
        break  
    }  
}
複製程式碼

case:該語句在 switch 語句中列出,在每個分支可以進行模式匹配。

let box = 1

switch box  
{  
    case 0:  
    print("Box equals 0")  
    case 1:  
    print("Box equals 1")  
    default:  
    print("Box doesn't equal 0 or 1")  
}
複製程式碼

continue:用於終止迴圈的當前迭代,並進入下一次迭代,而不會停止整個迴圈的執行。

for idx in 0...3  
{  
    if idx % 2 == 0  
    {  
        //直接開始迴圈的下一次迭代
        continue  
    }

    print("This code never fires on even numbers")  
}
複製程式碼

default:用於涵蓋在 switch 語句中,所有未明確列出的列舉成員。

let box = 1

switch box  
{  
    case 0:  
    print("Box equals 0")  
    case 1:  
    print("Box equals 1")  
    default:  
    print("Covers any scenario that doesn't get addressed above.")  
}
複製程式碼

defer:用於在程式離開當前作用域之前,執行一段程式碼。

func cleanUpIO()  
{  
    defer  
    {  
        print("This is called right before exiting scope")  
    }


    //關閉檔案流等。  
}
複製程式碼

do:用於表示處理錯誤程式碼段的開始。

do  
{  
    try expression  
    //語句
}  
catch someError ex  
{  
    //處理錯誤
}
複製程式碼

else:與 if 語句結合使用。當條件為 true,執行一段程式碼。當條件為 false,執行另一段程式碼。

if val > 1  
{  
    print("val is greater than 1")  
}  
else  
{  
    print("val is not greater than 1")  
}
複製程式碼

fallthrough:顯式地允許從當前 case 跳轉到下一個相鄰 case 繼續執行程式碼。

let box = 1

switch box  
{  
    case 0:  
    print("Box equals 0")  
    fallthrough  
    case 1:  
    print("Box equals 0 or 1")  
    default:  
    print("Box doesn't equal 0 or 1")  
}
複製程式碼

for:在序列上迭代,比如一組特定範圍內的數字,陣列中的元素,字串中的字元。*與關鍵字 in 成對使用。

for _ in 0..<3 { print ("This prints 3 times") }
複製程式碼

guard:當有一個以上的條件不滿足要求時,將離開當前作用域。同時還提供解包可選型別的功能。

private func printRecordFromLastName(userLastName: String?)
{  
    guard let name = userLastName, name != "Null" else  
    {  
        //userLastName = "Null",需要提前退出
        return  
    }

    //繼續執行程式碼
    print(dataStore.findByLastName(name))  
}
複製程式碼

if:當條件滿足時,執行程式碼。

if 1 > 2  
{  
    print("This will never execute")  
}
複製程式碼

in:在序列上迭代,比如一組特定範圍內的數字,陣列中的元素,字串中的字元。*與關鍵字 key 搭配使用。

for _ in 0..<3 { print ("This prints 3 times") }
複製程式碼

repeat:在使用迴圈的判斷條件之前,先執行一次迴圈中的程式碼。

repeat  
{  
    print("Always executes at least once before the condition is considered")  
}  
while 1 > 2
複製程式碼

return:立刻終止當前上下文,離開當前作用域,此外在返回時可以額外攜帶一個值。

func doNothing()  
{  
    return //直接離開當前上下文

    let anInt = 0  
    print("This never prints (anInt)")  
}
複製程式碼

func returnName() -> String?  
{  
    return self.userName //離開,並返回 userName 的值
}
複製程式碼

switch:將給定的值與分支進行比較。執行第一個模式匹配成功的分支程式碼。

let box = 1

switch box  
{  
    case 0:  
    print("Box equals 0")  
    fallthrough  
    case 1:  
    print("Box equals 0 or 1")  
    default:  
    print("Box doesn't equal 0 or 1")  
}
複製程式碼

where:要求關聯型別必須遵守特定協議,或者型別引數和關聯型別必須保持一致。也可以用於在 case 中提供額外條件,用於滿足控制表示式。

where 從句可以應用於多種場景。以下例子指明瞭 where 的主要應用場景,泛型中的模式匹配。

protocol Nameable  
{  
    var name:String {get set}  
}

func createdFormattedName(_ namedEntity:T) -> String where T:Equatable  
{  
    //只有當實體同時遵守 Nameable 和 Equatable 協議的時候,才允許呼叫這個函式
    return "This things name is " + namedEntity.name  
}
複製程式碼

for i in 0…3 where i % 2 == 0  
{  
    print(i) //列印 0 和 2  
}
複製程式碼

while:迴圈執行特定的一段語句,直到條件不滿足時,停止迴圈。

while foo != bar  
{  
    print("Keeps going until the foo == bar")  
}
複製程式碼

表示式和型別中的關鍵字

Any:用於表示任意型別的例項,包括函式型別。

var anything = [Any]()

anything.append("Any Swift type can be added")  
anything.append(0)  
anything.append({(foo: String) -> String in "Passed in (foo)"})
複製程式碼

as:型別轉換運算子,用於嘗試將值轉成其它型別。

var anything = [Any]()

anything.append("Any Swift type can be added")  
anything.append(0)  
anything.append({(foo: String) -> String in "Passed in (foo)" })

let intInstance = anything[1] as? Int
複製程式碼

或者

var anything = [Any]()

anything.append("Any Swift type can be added")  
anything.append(0)  
anything.append({(foo: String) -> String in "Passed in (foo)" })

for thing in anything  
{  
    switch thing  
    {  
        case 0 as Int:  
        print("It's zero and an Int type")  
        case let someInt as Int:  
        print("It's an Int that's not zero but (someInt)")  
        default:  
        print("Who knows what it is")  
    }  
}
複製程式碼

catch:如果在 do 中丟擲一個錯誤,catch 會嘗試進行匹配,並決定如何處理錯誤。*我寫的一篇 Swift 錯誤處理的部落格節選

do  
{  
    try haveAWeekend(4)  
}  
catch WeekendError.Overtime(let hoursWorked)  
{  
    print("You worked (hoursWorked) more than you should have")  
}  
catch WeekendError.WorkAllWeekend  
{  
    print("You worked 48 hours :-0")  
}  
catch  
{  
    print("Gulping the weekend exception")  
}
複製程式碼

false:Swift 用於表示布林值的兩個常量值之一,true 的相反值。

let alwaysFalse = false  
let alwaysTrue = true

if alwaysFalse { print("Won't print, alwaysFalse is false ?")}
複製程式碼

is:型別檢查運算子,用於確定例項是否為某個子類型別。

class Person {}  
class Programmer : Person {}  
class Nurse : Person {}

let people = [Programmer(), Nurse()]

for aPerson in people  
{  
    if aPerson is Programmer  
    {  
        print("This person is a dev")  
    }  
    else if aPerson is Nurse  
    {  
        print("This person is a nurse")  
    }  
}
複製程式碼

nil:在 Swift 中表示任意型別的無狀態值。

與 Objective-C 中的 nil 不同,Objective-C 中的 nil 表示指向不存在物件的指標。

class Person{}  
struct Place{}

//任何 Swift 型別或例項可以為 nil
var statelessPerson:Person? = nil  
var statelessPlace:Place? = nil  
var statelessInt:Int? = nil  
var statelessString:String? = nil
複製程式碼

rethrows:指明當前函式只有當引數丟擲 error 時,才會丟擲 error。

func networkCall(onComplete:() throws -> Void) rethrows  
{  
    do  
    {  
        try onComplete()  
    }  
    catch  
    {  
        throw SomeError.error  
    }  
}
複製程式碼

super:在子類中,暴露父類的方法、屬性、下標。

class Person  
{  
    func printName()  
    {  
        print("Printing a name. ")  
    }  
}

class Programmer : Person  
{  
    override func printName()  
    {  
        super.printName()  
        print("Hello World!")  
    }  
}

let aDev = Programmer()  
aDev.printName() //列印 Printing a name. Hello World!
複製程式碼

self:任何型別的例項都擁有的隱式屬性,等同於例項本身。此外還可以用於區分函式引數和成員屬性名稱相同的情況。

class Person  
{  
    func printSelf()  
    {  
        print("This is me: (self)")  
    }  
}

let aPerson = Person()  
aPerson.printSelf() //列印 "This is me: Person"
複製程式碼

Self:在協議中,表示遵守當前協議的實體型別。

protocol Printable  
{  
    func printTypeTwice(otherMe:Self)  
}

struct Foo : Printable  
{  
    func printTypeTwice(otherMe: Foo)  
    {  
        print("I am me plus (otherMe)")  
    }  
}

let aFoo = Foo()  
let anotherFoo = Foo()

aFoo.printTypeTwice(otherMe: anotherFoo) //列印 I am me plus Foo()
複製程式碼

throw:用於在當前上下文,顯式丟擲 error。

enum WeekendError: Error  
{  
    case Overtime  
    case WorkAllWeekend  
}

func workOvertime () throws  
{  
    throw WeekendError.Overtime  
}
複製程式碼

throws:指明在一個函式、方法、初始化方法中可能會丟擲 error。

enum WeekendError: Error  
{  
    case Overtime  
    case WorkAllWeekend  
}

func workOvertime () throws  
{  
    throw WeekendError.Overtime  
}

//"throws" 表明在呼叫方法時,需要使用 try,try?,try!
try workOvertime()
複製程式碼

true:Swift 用於表示布林值的兩個常量值之一,表示為真。

let alwaysFalse = false  
let alwaysTrue = true

if alwaysTrue { print("Always prints")}
複製程式碼

try:表明接著呼叫的函式可能會丟擲 error。有三種不同的使用方式:try,try?, try!。

let aResult = try dangerousFunction() //處理 error,或者繼續傳遞 error  
let aResult = try! dangerousFunction() //程式可能會閃退  
if let aResult = try? dangerousFunction() //解包可選型別。
複製程式碼

模式中的關鍵字

_:用於匹配或省略任意值的萬用字元。

for _ in 0..<3  
{  
    print("Just loop 3 times, index has no meaning")  
}
複製程式碼

另外一種用法:

let _ = Singleton() //忽略不使用的變數
複製程式碼

以#開頭的關鍵字

#available:基於平臺引數,通過 ifwhileguard 語句的條件,在執行時檢查 API 的可用性。

if #available(iOS 10, *)  
{  
    print("iOS 10 APIs are available")  
}
複製程式碼

#colorLiteral:在 playground 中使用的字面表示式,用於建立顏色選取器,選取後賦值給變數。

let aColor = #colorLiteral //建立顏色選取器
複製程式碼

#column:一種特殊的字面量表示式,用於獲取字面量表示式的起始列數。

class Person  
{  
    func printInfo()  
    {  
        print("Some person info - on column (#column)")
    }  
}

let aPerson = Person()  
aPerson.printInfo() //Some person info - on column 53
複製程式碼

#else:條件編譯控制語句,用於控制程式在不同條件下執行不同程式碼。與 #if 語句結合使用。當條件為 true,執行對應程式碼。當條件為 false,執行另一段程式碼。

#if os(iOS)  
print("Compiled for an iOS device")  
#else  
print("Not on an iOS device")  
#endif
複製程式碼

#elseif:條件編譯控制語句,用於控制程式在不同條件下執行程式碼。與 #if 語句結合使用。當條件為 true,執行對應程式碼。

#if os(iOS)  
print("Compiled for an iOS device")  
#elseif os(macOS)  
print("Compiled on a mac computer")  
#endif
複製程式碼

#endif:條件編譯控制語句,用於控制程式在不同條件下執行程式碼。用於表明條件編譯程式碼的結尾。

#if os(iOS)  
print("Compiled for an iOS device")  
#endif
複製程式碼

#file:特殊字面量表示式,返回當前程式碼所在原始檔的名稱。

class Person  
{  
    func printInfo()  
    {  
        print("Some person info - inside file (#file)")
    }  
}

let aPerson = Person()  
aPerson.printInfo() //Some person info - inside file /*程式碼所在 playground 檔案路徑*/
複製程式碼

#fileReference:playground 字面量語法,用於建立檔案選取器,選取並返回 NSURL 例項。

let fontFilePath = #fileReference //建立檔案選取器
複製程式碼

#function:特殊字面量表示式,返回函式名稱。在方法中,返回方法名。在屬性的 getter 或者 setter 中,返回屬性名。在特殊的成員中,比如 init 或 subscript 中,返回關鍵字名稱。在檔案的最頂層時,返回當前所在模組名稱。

class Person  
{  
    func printInfo()  
    {  
        print("Some person info - inside function (#function)")
    }  
}

let aPerson = Person()  
aPerson.printInfo() //Some person info - inside function printInfo()
複製程式碼

#if:條件編譯控制語句,用於控制程式在不同條件下編譯程式碼。通過判斷條件,決定是否執行程式碼。

#if os(iOS)  
print("Compiled for an iOS device")  
#endif
複製程式碼

#imageLiteral:playground 字面量語法,建立圖片選取器,選擇並返回 UIImage 例項。

let anImage = #imageLiteral //在 playground 檔案中選取圖片
複製程式碼

#line:特殊字面量表示式,用於獲取當前程式碼的行數。

class Person  
{  
    func printInfo()  
    {  
        print("Some person info - on line number (#line)")
    }  
}

let aPerson = Person()  
aPerson.printInfo() //Some person info - on line number 5
複製程式碼

#selector:用於建立 Objective-C selector 的表示式,可以靜態檢查方法是否存在,並暴露給 Objective-C。

//靜態檢查,確保 doAnObjCMethod 方法存在  
control.sendAction(#selector(doAnObjCMethod), to: target, forEvent: event)
複製程式碼

#sourceLocation:行控制語句,可以指定與原先完全不同的行數和原始檔名。通常在 Swift 診斷、debug 時使用。

#sourceLocation(file:"foo.swift", line:6)

//列印新值
print(#file)  
print(#line)

//重置行數和檔名
#sourceLocation()

print(#file)  
print(#line)
複製程式碼

特定上下文中的關鍵字

這些關鍵字,在處於對應上下文之外時,可以用作識別符號。

associativity:指明同一優先順序的運算子,在缺少大括號的情況,按什麼順序結合。使用 leftrightnone

infix operator ~ { associativity right precedence 140 }  
4 ~ 8
複製程式碼

convenience:次等的便利構造器,最後會呼叫指定構造器初始化例項。

class Person  
{  
    var name:String

    init(_ name:String)  
    {  
        self.name = name  
    }

    convenience init()  
    {  
        self.init("No Name")  
    }  
}

let me = Person()  
print(me.name)//列印 "No Name"
複製程式碼

dynamic:指明編譯器不會對類成員或者函式的方法進行內聯或虛擬化。這意味著對這個成員的訪問是使用 Objective-C 執行時進行動態派發的(代替靜態呼叫)。

class Person  
{  
    //隱式指明含有 "objc" 屬性
    //這對依賴於 Objc-C 黑魔法的庫或者框架非常有用
    //比如 KVO、KVC、Swizzling
    dynamic var name:String?  
}
複製程式碼

didSet:屬性觀察者,當值儲存到屬性後馬上呼叫。

var data = [1,2,3]  
{  
    didSet  
    {  
        tableView.reloadData()  
    }  
}
複製程式碼

final:防止方法、屬性、下標被重寫。

final class Person {}  
class Programmer : Person {} //編譯錯誤
複製程式碼

get:返回成員的值。還可以用在計算型屬性上,間接獲取其它屬性的值。

class Person  
{  
    var name:String  
    {  
        get { return self.name }  
        set { self.name = newValue}  
    }

    var indirectSetName:String  
    {  
        get  
        {  
            if let aFullTitle = self.fullTitle  
            {  
                return aFullTitle  
            }  
            return ""  
        }

        set (newTitle)  
        {  
            //如果沒有定義 newTitle,可以使用 newValue
            self.fullTitle = "(self.name) :(newTitle)"  
        }
    }  
}
複製程式碼

infix:指明一個用於兩個值之間的運算子。如果一個全新的全域性運算子被定義為 infix,還需要指定優先順序。

let twoIntsAdded = 2 + 3
複製程式碼

indirect:指明在列舉型別中,存在成員使用相同列舉型別的例項作為關聯值的情況。

indirect enum Entertainment  
{  
    case eventType(String)  
    case oneEvent(Entertainment)  
    case twoEvents(Entertainment, Entertainment)  
}

let dinner = Entertainment.eventType("Dinner")  
let movie = Entertainment.eventType("Movie")

let dateNight = Entertainment.twoEvents(dinner, movie)
複製程式碼

lazy:指明屬性的初始值,直到第一次被使用時,才進行初始化。

class Person  
{  
    lazy var personalityTraits = {  
        //昂貴的資料庫開銷  
        return ["Nice", "Funny"]  
    }()  
}
let aPerson = Person()  
aPerson.personalityTraits //當 personalityTraits 首次被訪問時,資料庫才開始工作
複製程式碼

left:指明運算子的結合性是從左到右。在沒有使用大括號時,可以用於正確判斷同一優先順序運算子的執行順序。

//"-" 運算子的結合性是從左到右
10-2-4 //根據結合性,可以看做 (10-2) - 4
複製程式碼

mutating:允許在方法中修改結構體或者列舉例項的屬性值。

struct Person  
{  
    var job = ""

    mutating func assignJob(newJob:String)  
    {  
        self = Person(job: newJob)  
    }  
}

var aPerson = Person()  
aPerson.job //""

aPerson.assignJob(newJob: "iOS Engineer at Buffer")  
aPerson.job //iOS Engineer at Buffer
複製程式碼

none:是一個沒有結合性的運算子。不允許這樣的運算子相鄰出現。

//"<" 是非結合性的運算子
1 < 2 < 3 //編譯失敗
複製程式碼

nonmutating:指明成員的 setter 方法不會修改例項的值,但可能會有其它後果。

enum Paygrade  
{  
    case Junior, Middle, Senior, Master

    var experiencePay:String?  
    {  
        get  
        {  
            database.payForGrade(String(describing:self))  
        }

        nonmutating set  
        {  
            if let newPay = newValue  
            {  
                database.editPayForGrade(String(describing:self), newSalary:newPay)  
            }  
        }  
    }  
}

let currentPay = Paygrade.Middle

//將 Middle pay 更新為 45k, 但不會修改 experiencePay 值
currentPay.experiencePay = "$45,000"
複製程式碼

optional:用於指明協議中的可選方法。遵守該協議的實體類可以不實現這個方法。

@objc protocol Foo  
{  
    func requiredFunction()  
    @objc optional func optionalFunction()  
}

class Person : Foo  
{  
    func requiredFunction()  
    {  
        print("Conformance is now valid")  
    }  
}
複製程式碼

override:指明子類會提供自定義實現,覆蓋父類的例項方法、型別方法、例項屬性、型別屬性、下標。如果沒有實現,則會直接繼承自父類。

class Person  
{  
    func printInfo()  
    {  
        print("I'm just a person!")  
    }  
}

class Programmer : Person  
{  
    override func printInfo()  
    {  
        print("I'm a person who is a dev!")  
    }  
}

let aPerson = Person()  
let aDev = Programmer()

aPerson.printInfo() //列印 I'm just a person!  
aDev.printInfo() //列印 I'm a person who is a dev!
複製程式碼

postfix:位於值後面的運算子。

var optionalStr:String? = "Optional"  
print(optionalStr!)
複製程式碼

precedence:指明某個運算子的優先順序高於別的運算子,從而被優先使用。

infix operator ~ { associativity right precedence 140 }  
4 ~ 8
複製程式碼

prefix:位於值前面的運算子。

var anInt = 2  
anInt = -anInt //anInt 等於 -2
複製程式碼

required:確保編譯器會檢查該類的所有子類,全部實現了指定的構造器方法。

class Person  
{  
    var name:String?

    required init(_ name:String)  
    {  
        self.name = name  
    }  
}

class Programmer : Person  
{  
    //如果不實現這個方法,編譯不會通過
    required init(_ name: String)  
    {  
        super.init(name)  
    }  
}
複製程式碼

right:指明運算子的結合性是從右到左的。在沒有使用大括號時,可以用於正確判斷同一優先順序運算子的順序。

//"??" 運算子結合性是從右到左
var box:Int?  
var sol:Int? = 2

let foo:Int = box ?? sol ?? 0 //Foo 等於 2
複製程式碼

set:通過獲取的新值來設定成員的值。同樣可以用於計算型屬性來間接設定其它屬性。如果計算型屬性的 setter 沒有定義新值的名稱,可以使用預設的 newValue。

class Person  
{  
    var name:String  
    {  
        get { return self.name }  
        set { self.name = newValue}  
    }

    var indirectSetName:String  
    {  
        get  
        {  
            if let aFullTitle = self.fullTitle  
            {  
                return aFullTitle  
            }  
            return ""  
        }

        set (newTitle)  
        {  
            //如果沒有定義 newTitle,可以使用 newValue
            self.fullTitle = "(self.name) :(newTitle)"  
        }  
    }  
}
複製程式碼

Type:表示任意型別的型別,包括類型別、結構型別、列舉型別、協議型別。

class Person {}  
class Programmer : Person {}

let aDev:Programmer.Type = Programmer.self
複製程式碼

unowned:讓迴圈引用中的例項 A 不要強引用例項 B。前提條件是例項 B 的生命週期要長於 A 例項。

class Person  
{  
    var occupation:Job?  
}

//當 Person 例項不存在時,job 也不會存在。job 的生命週期取決於持有它的 Person。
class Job  
{  
    unowned let employee:Person

    init(with employee:Person)  
    {  
        self.employee = employee  
    }  
}
複製程式碼

weak:允許迴圈引用中的例項 A 弱引用例項 B ,而不是強引用。例項 B 的生命週期更短,並會被先釋放。

class Person  
{  
    var residence:House?  
}

class House  
{  
    weak var occupant:Person?  
}

var me:Person? = Person()  
var myHome:House? = House()

me!.residence = myHome  
myHome!.occupant = me

me = nil  
myHome!.occupant // myHome 等於 nil
複製程式碼

willSet:屬性觀察者,在值儲存到屬性之前呼叫。

class Person  
{  
    var name:String?  
    {  
        willSet(newValue) {print("I've got a new name, it's (newValue)!")}  
    }  
}

let aPerson = Person()  
aPerson.name = "Jordan" //在賦值之前,列印 "I've got a new name, it's Jordan!"
複製程式碼

總結

哇噢!

這真是一次有趣的創作。我學會了好多在寫之前沒想到的東西。但我認為這裡的訣竅並不是要把它記住,而是把它當做一份可以用於測驗的定義清單。

相反地,我建議你把這份清單放在手邊,並時不時地回顧一下。如果你能這樣做的話,下一次在不同場景下需要使用特定的關鍵字,你肯定就能馬上回想起來並使用它啦。

下回再見咯。

本文由 SwiftGG 翻譯組翻譯,已經獲得作者翻譯授權,最新文章請訪問 swift.gg