Swift 關(guān)鍵字

deinit: 當(dāng)一個(gè)類的實(shí)例即將被銷毀時(shí),會(huì)調(diào)用這個(gè)方法草姻。

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

    deinit  
    {  
        //從堆中釋放钓猬,并釋放的資源
    }  
}

extension:允許給已有的類、結(jié)構(gòu)體碴倾、枚舉逗噩、協(xié)議類型,添加新功能跌榔。

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:訪問控制權(quán)限异雁,只允許在定義源文件中訪問。

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

extension Person  
{
    //當(dāng) extension 和 class 在同一個(gè)文件中時(shí)僧须,允許訪問
    func printJobTitle()  
    {  
        print("My job is (jobTitle)")  
    }  
}

inout:將一個(gè)值傳入函數(shù)纲刀,并可以被函數(shù)修改,然后將值傳回到調(diào)用處担平,來替換初始值示绊。適用于引用類型和值類型。 其實(shí)就是聲明參數(shù)為指針

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

var potentialError:NSError?
dangerousOp(&potentialError)

//代碼運(yùn)行到這里暂论,potentialError 不再是 nil面褐,而是已經(jīng)被初始化

internal:訪問控制權(quán)限,允許同一個(gè)模塊下的所有源文件訪問取胎,如果在不同模塊下則不允許訪問展哭。

open:訪問控制權(quán)限,允許在定義的模塊外也可以訪問源文件里的所有類闻蛀,并進(jìn)行子類化匪傍。對(duì)于類成員,允許在定義的模塊之外訪問和重寫觉痛。

open var foo:String? //這個(gè)屬性允許在 app 內(nèi)或 app 外重寫和訪問役衡。在開發(fā)框架的時(shí)候,會(huì)應(yīng)用到這個(gè)訪問修飾符薪棒。

private:訪問控制權(quán)限手蝎,只允許實(shí)體在定義的類以及相同源文件內(nèi)的 extension 中訪問榕莺。

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

// 當(dāng) extension 和 class 不在同一個(gè)源文件時(shí)
extension Person  
{
    // 無法編譯通過,只有在同一個(gè)源文件下才可以訪問
    func printJobTitle()  
    {  
        print("My job is (jobTitle)")  
    }  
}

public:訪問控制權(quán)限柑船,允許在定義的模塊外也可以訪問源文件里的所有類帽撑,但只有在同一個(gè)模塊內(nèi)可以進(jìn)行子類化。對(duì)于類成員鞍时,允許在同個(gè)模塊下訪問和重寫。

public var foo:String? //只允許在 app 內(nèi)重寫和訪問扣蜻。

static:用于定義類方法逆巍,在類型本身進(jìn)行調(diào)用。此外還可以定義靜態(tài)成員莽使。

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:通用锐极、靈活的結(jié)構(gòu)體,是程序的基礎(chǔ)組成部分芳肌,并提供了默認(rèn)初始化方法灵再。與 class 不同,當(dāng) struct 在代碼中被傳遞時(shí)亿笤,是被拷貝的翎迁,并不使用引用計(jì)數(shù)。除此之外净薛,struct 沒有下面的這些功能:

  • 使用繼承汪榔。
  • 運(yùn)行時(shí)的類型轉(zhuǎn)換。
  • 使用析構(gòu)方法肃拜。
struct Person  
{  
    var name:String  
    var age:Int  
    var gender:String  
}

typealias:給代碼中已經(jīng)存在的類痴腌,取別名。

typealias JSONDictionary = [String: AnyObject]

func parseJSON(_ deserializedData:JSONDictionary){}

defer:用于在程序離開當(dāng)前作用域之前燃领,執(zhí)行一段代碼士聪。

關(guān)閉文件

func foo() {
  let fileDescriptor = open(url.path, O_EVTONLY)
  defer {
    close(fileDescriptor)
  }
  // use fileDescriptor...
}

加/解鎖:下面是 swift 里類似 Objective-C 的 synchronized block 的一種寫法,可以使用任何一個(gè) NSObject 作 lock

func foo() {
  objc_sync_enter(lock)
  defer { 
    objc_sync_exit(lock)
  }
  // do something...
}

defer 的執(zhí)行時(shí)機(jī):
defer 的執(zhí)行時(shí)機(jī)緊接在離開作用域之后猛蔽,但是是在其他語句之前剥悟。這個(gè)特性為 defer 帶來了一些很“微妙”的使用方式。比如從 0 開始的自增:

class Foo {
    var num = 0
    func foo() -> Int {
        defer { num += 1 }
        return num
    }
    
    // 沒有 `defer` 的話我們可能要這么寫
    // func foo() -> Int {
    //    num += 1
    //    return num - 1
    // }
}

let f = Foo()
f.foo() // 0
f.foo() // 1
f.num   // 2

fallthrough:顯式地允許從當(dāng)前 case 跳轉(zhuǎn)到下一個(gè)相鄰 case 繼續(xù)執(zhí)行代碼枢舶。

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")  
}

guard:當(dāng)有一個(gè)以上的條件不滿足要求時(shí)懦胞,將離開當(dāng)前作用域。同時(shí)還提供解包可選類型的功能凉泄。

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

    //繼續(xù)執(zhí)行代碼
    print(dataStore.findByLastName(name))  
}

1.guard關(guān)鍵字必須使用在函數(shù)中。
2.guard關(guān)鍵字必須和else同時(shí)出現(xiàn)后众。
3.guard關(guān)鍵字只有條件為false的時(shí)候才能走else語句 相反執(zhí)行后邊語句胀糜。

repeat:在使用循環(huán)的判斷條件之前颅拦,先執(zhí)行一次循環(huán)中的代碼。

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

where:要求關(guān)聯(lián)類型必須遵守特定協(xié)議教藻,或者類型參數(shù)和關(guān)聯(lián)類型必須保持一致距帅。也可以用于在 case 中提供額外條件,用于滿足控制表達(dá)式括堤。

  • 增加判斷條件
for i in 0…3 where i % 2 == 0  
{  
    print(i) //打印 0 和 2  
}
  • 協(xié)議使用where碌秸, 只有基類實(shí)現(xiàn)了當(dāng)前協(xié)議才能添加擴(kuò)展。 換個(gè)說法悄窃, 多個(gè)類實(shí)現(xiàn)了同一個(gè)協(xié)議讥电,該語法根據(jù)類名分別為這些類添加擴(kuò)展, 注意是分別(以類名區(qū)分)T埂6鞯小!
protocol SomeProtocol {
    func someMethod()
}
 
class A: SomeProtocol {
    let a = 1
    
    func someMethod() {
       print("call someMethod")
    }
}
 
class B {
    let a = 2
}
 
//基類A繼承了SomeProtocol協(xié)議才能添加擴(kuò)展
extension SomeProtocol where Self: A {
    func showParamA() {
        print(self.a)
    }
}
//反例横媚,不符合where條件
extension SomeProtocol where Self: B {
    func showParamA() {
        print(self.a)
    }
}
let objA = A()
let objB = B()  //類B沒實(shí)現(xiàn)SomeProtocol纠炮, 所有沒有協(xié)議方法
objA.showParamA()  //輸出1

as:類型轉(zhuǎn)換運(yùn)算符,用于嘗試將值轉(zhuǎn)成其它類型灯蝴。

  • as : 數(shù)值類型轉(zhuǎn)換
let age = 28 as Int
let money = 20 as CGFloat
let cost = (50 / 2) as Double
switch person1 { 
  case let person1 as Student: 
    print("是Student類型恢口,打印學(xué)生成績單...") 
  case let person1 as Teacher: 
    print("是Teacher類型,打印老師工資單...") 
  default: break
}
  • as!:向下轉(zhuǎn)型(Downcasting)時(shí)使用绽乔。由于是強(qiáng)制類型轉(zhuǎn)換弧蝇,如果轉(zhuǎn)換失敗會(huì)報(bào) runtime 運(yùn)行錯(cuò)誤。
let person : Person = Teacher("Jimmy Lee")
let jimmy = person as! Teacher
  • as?: as? 和 as! 操作符的轉(zhuǎn)換規(guī)則完全一樣折砸。但 as? 如果轉(zhuǎn)換不成功的時(shí)候便會(huì)返回一個(gè) nil 對(duì)象看疗。成功的話返回可選類型值。由于 as? 在轉(zhuǎn)換失敗的時(shí)候也不會(huì)出現(xiàn)錯(cuò)誤睦授,所以對(duì)于如果能確保100%會(huì)成功的轉(zhuǎn)換則可使用 as!两芳,否則使用 as?
let a = 13 as! String
print(a)
//會(huì)crash
let a = 13 as? String
print(a)
//輸出為nil

is:類型檢查運(yùn)算符,用于確定實(shí)例是否為某個(gè)子類類型去枷。

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 中表示任意類型的無狀態(tài)值怖辆。

Swift的nil和OC中的nil不一樣.在OC中,nil是一個(gè)指向不存在對(duì)象的指針.而在Swift中,nil不是指針,它是一個(gè)不確定的值.用來表示值缺失.任何類型的optional都可以被設(shè)置為nil. 而在OC中,基本數(shù)據(jù)類型和結(jié)構(gòu)體是不能被設(shè)置為nil的. 給optional的常量或者變量賦值為nil.來表示他們的值缺失情況.一個(gè)optional常量或者變量如果在初始化的時(shí)候沒有被賦值,他們自動(dòng)會(huì)設(shè)置成nil.

class Person{}  
struct Place{}

//任何 Swift 類型或?qū)嵗梢詾?nil
var statelessPerson:Person? = nil  
var statelessPlace:Place? = nil  
var statelessInt:Int? = nil  
var statelessString:String? = nil

super:在子類中,暴露父類的方法删顶、屬性竖螃、下標(biāo)。

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:任何類型的實(shí)例都擁有的隱式屬性逗余,等同于實(shí)例本身特咆。此外還可以用于區(qū)分函數(shù)參數(shù)和成員屬性名稱相同的情況。

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

let aPerson = Person()  
aPerson.printSelf() //打印 "This is me: Person"

Self:在協(xié)議中,表示遵守當(dāng)前協(xié)議的實(shí)體類型洁奈。

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

_:用于匹配或省略任意值的通配符。

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

另外一種用法:

let _ = Singleton() //忽略不使用的變量

以#開頭的關(guān)鍵字


#available:基于平臺(tái)參數(shù)夺谁,通過 if菜职,while青抛,guard 語句的條件,在運(yùn)行時(shí)檢查 API 的可用性酬核。
if #available(iOS 10, *)  
{  
    print("iOS 10 APIs are available")  
}
#colorLiteral:在 playground 中使用的字面表達(dá)式蜜另,用于創(chuàng)建顏色選取器,選取后賦值給變量愁茁。
let aColor = #colorLiteral //創(chuàng)建顏色選取器

#column:一種特殊的字面量表達(dá)式蚕钦,用于獲取字面量表示式的起始列數(shù)。
class Person  
{  
    func printInfo()  
    {  
        print("Some person info - on column (#column)")
    }  
}

let aPerson = Person()  
aPerson.printInfo() //Some person info - on column 53
#function:特殊字面量表達(dá)式鹅很,返回函數(shù)名稱。在方法中罪帖,返回方法名促煮。在屬性的 getter 或者 setter 中,返回屬性名整袁。在特殊的成員中菠齿,比如 init 或 subscript 中,返回關(guān)鍵字名稱坐昙。在文件的最頂層時(shí)绳匀,返回當(dāng)前所在模塊名稱。
class Person  
{  
    func printInfo()  
    {  
        print("Some person info - inside function (#function)")
    }  
}

let aPerson = Person()  
aPerson.printInfo() //Some person info - inside function printInfo()
#line:特殊字面量表達(dá)式炸客,用于獲取當(dāng)前代碼的行數(shù)疾棵。
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:用于創(chuàng)建 Objective-C selector 的表達(dá)式,可以靜態(tài)檢查方法是否存在痹仙,并暴露給 Objective-C是尔。
//靜態(tài)檢查,確保 doAnObjCMethod 方法存在  
control.sendAction(#selector(doAnObjCMethod), to: target, forEvent: event)


convenience:

在 Swift 中开仰,為保證安全性拟枚,init 方法只能調(diào)用一次,且在 init 完成后众弓,保證所有非 Optional 的屬性都已經(jīng)被初始化恩溅。

每個(gè)類都有指定的初始化方法:designated initializer,這些初始化方法是子類必須調(diào)用的谓娃,為的就是保證父類的屬性都初始化完成了脚乡。

而如果不想實(shí)現(xiàn)父類的 designated initializer,可以添加 convenience 關(guān)鍵字傻粘,自己實(shí)現(xiàn)初始化邏輯每窖。
convenience 初始化不能調(diào)用父類的初始化方法帮掉,只能調(diào)用同一個(gè)類中的 designated initializer。
由于 convenience 初始化不安全窒典,所以 Swift 不允許 convenience initializer 被子類重寫蟆炊,限制其作用范圍。

class People {
    
    var name: String
    
    init(name: String) {
        self.name = name
    }
}

通過extension給原有的People類增加init方法:

// 使用convenience增加init方法
extension People {
    convenience init(smallName: String) {
        self.init(name: smallName)
    }
}

結(jié)下來瀑志,Student類繼承父類People

class Student: People {
    var grade: Int
    
    init(name: String, grade: Int) {
        self.grade = grade
        super.init(name: name)
        // 無法調(diào)用
        // super.init(smallName: name)
    }
    
    // 可以被重寫 
    override init(name: String) {
        grade = 1
        super.init(name: name)
    }
    
    // 無法重寫涩搓,編譯不通過
    override init(smallName: String) {
        grade = 1
        super.init(smallName: smallName)
    }
}

子類對(duì)象調(diào)用父類的convenience的init方法:只要在子類中實(shí)現(xiàn)重寫了父類convenience方法所需要的init方法的話,我們在子類中就可以使用父類的convenience初始化方法了

class People {
    
    var name: String
    
    init(name: String) {
        self.name = name
    }
}
// 使用convenience增加init方法
extension People {
    convenience init(smallName: String) {
        self.init(name: smallName)
    }
}


// 子類
class Teacher: People {
    
    var course: String
    
    init(name: String, course: String) {
        self.course = course
        super.init(name: name)
    }
    
    override init(name: String) {
        self.course = "math"
        super.init(name: name)
    }
}

// 調(diào)用convenience的init方法
let xiaoming = Teacher(smallName: "xiaoming")
  • 總結(jié):子類的designated初始化方法必須調(diào)用父類的designated方法劈猪,以保證父類也完成初始化昧甘。

required關(guān)鍵字

對(duì)于某些我們希望子類中一定實(shí)現(xiàn)的designated初始化方法,我們可以通過添加required關(guān)鍵字進(jìn)行限制战得,強(qiáng)制子類對(duì)這個(gè)方法重寫充边。
required修飾符的使用規(guī)則:

  • required修飾符只能用于修飾類初始化方法。
  • 當(dāng)子類含有異于父類的初始化方法時(shí)(初始化方法參數(shù)類型和數(shù)量異于父類)常侦,子類必須要實(shí)現(xiàn)父類的required初始化方法浇冰,并且也要使用required修飾符而不是override。
  • 當(dāng)子類沒有初始化方法時(shí)聋亡,可以不用實(shí)現(xiàn)父類的required初始化方法肘习。

代碼:

        class MyClass {
            var str:String
            required init(str:String) {
                self.str = str
            }
        }
        class MySubClass:MyClass
        {
            init(i:Int) {
                super.init(str:String(i))
            }
            
        }
        // 編譯錯(cuò)誤
        MySubClass(i: 123)

會(huì)報(bào)錯(cuò),因?yàn)槟銢]有實(shí)現(xiàn)父類中必須實(shí)現(xiàn)的方法坡倔。正確的寫法:

    class MyClass{
        var str: String?
        required init(str: String?) {
            self.str = str
        }
    }
    class MySubClass: MyClass{
        init(i: Int) {
            super.init(str: String(i))
        }
        
        required init(str: String?) {
            fatalError("init(str:) has not been implemented")
        }
    }

從上面的代碼中漂佩,不難看出子類需要添加異于父類的初始化方法,必須要重寫有required的修飾符的初始化方法罪塔,并且也要使用required修飾符而不是override投蝉,請千萬注意!

如果子類中并沒有不同于父類的初始化方法垢袱,Swift會(huì)默認(rèn)使用父類的初始化方法:

    class MyClass{
        var str: String?
        required init(str: String?) {
            self.str = str
        }
    }
    class MySubClass: MyClass{
    }
    var MySubClass(str: "hello swift")

在這種情況下墓拜,編譯器不會(huì)報(bào)錯(cuò),因?yàn)槿绻宇悰]有任何初始化方法時(shí)请契,Swift會(huì)默認(rèn)使用父類的初始化方法咳榜。

dynamic && @objc

1.@objc

OC 是基于運(yùn)行時(shí),遵循了 KVC 和動(dòng)態(tài)派發(fā)爽锥,而 Swift 為了追求性能涌韩,在編譯時(shí)就已經(jīng)確定,而不需要在運(yùn)行時(shí)的氯夷,在 Swift 類型文件中臣樱,為了解決這個(gè)問題,需要暴露給 OC 使用的任何地方(類,屬性雇毫,方法等)的生命前面加上 @objc 修飾符
如果用 Swift 寫的 class 是繼承 NSObject 的話玄捕, Swift 會(huì)默認(rèn)自動(dòng)為所有非 private 的類和成員加上@objc

在Swift中,我們在給button添加點(diǎn)擊事件時(shí)棚放,對(duì)應(yīng)的點(diǎn)擊事件的觸發(fā)方法就需要用@objc來修飾

2. dynamic

Swift 中的函數(shù)可以是靜態(tài)調(diào)用枚粘,靜態(tài)調(diào)用會(huì)更快。當(dāng)函數(shù)是靜態(tài)調(diào)用的時(shí)候飘蚯,就不能從字符串查找到對(duì)應(yīng)的方法地址了馍迄。這樣 Swift 跟 Objective-C 交互時(shí),Objective-C 動(dòng)態(tài)查找方法地址局骤,就有可能找不到 Swift 中定義的方法攀圈。

這樣就需要在 Swift 中添加一個(gè)提示關(guān)鍵字,告訴編譯器這個(gè)方法是可能被動(dòng)態(tài)調(diào)用的峦甩,需要將其添加到查找表中赘来。這個(gè)就是關(guān)鍵字 dynamic 的作用。

willSet與didSet

  • willSet在設(shè)置新的值之前調(diào)用凯傲。willSet可以帶一個(gè)newName的參數(shù)撕捍,沒有的話,該參數(shù)默認(rèn)命名為newValue
  • didSet在新的值被設(shè)置之后立即調(diào)用泣洞。didSet可以帶一個(gè)oldName的參數(shù),表示舊的屬性默色,不帶的話默認(rèn)命名為oldValue
  • willSet和didSet觀察器在屬性初始化過程中不會(huì)被調(diào)用球凰。只有在初始化上下文之外,當(dāng)設(shè)置屬性值時(shí)才會(huì)調(diào)用腿宰。
  • 即使是設(shè)置的值和原來值相同呕诉,willSet和didSet也會(huì)被調(diào)用
var counter: Int = 0{
        willSet(newTotal){
            print("計(jì)數(shù)器: \(newTotal)")
        }
        didSet{
            if counter > oldValue {
                print("新增數(shù) \(counter - oldValue)")
            }
        }
    }
let NewCounter = Samplepgm()
NewCounter.counter = 100
NewCounter.counter = 800
//結(jié)果:
//計(jì)數(shù)器: 100
//新增數(shù) 100
//計(jì)數(shù)器: 800
//新增數(shù) 700

final

  • final修飾符只能修飾類,表明該類不能被其他類繼承吃度,也就是它沒資格當(dāng)父類甩挫。
  • final修飾符也可以修飾類中的屬性、方法和下標(biāo)椿每,但前提是該類并沒有被final修飾過伊者。
  • final不能修飾結(jié)構(gòu)體和枚舉。

final正確的使用場景 - 權(quán)限控制
也就是說這個(gè)類或方法不希望被繼承和重寫间护,具體情況如下:

  • 類或者方法的功能確實(shí)已經(jīng)完備了
    這種通常是一些輔助性質(zhì)的工具類或者方法亦渗,特別那種只包含類方法而沒有實(shí)例方法的類。比如MD5加密類這種汁尺,算法都十分固定法精,我們基本不會(huì)再繼承和重寫。

  • 避免子類繼承和修改造成危險(xiǎn)
    有些方法如果被子類繼承重寫會(huì)造成破壞性的后果,導(dǎo)致無法正常工作搂蜓,則需要將其標(biāo)為final加以保護(hù)狼荞。

  • 為了讓父類中某些代碼一定會(huì)執(zhí)行
    父類的方法如果想要其中一些關(guān)鍵代碼在繼承重寫后仍必須執(zhí)行(比如狀態(tài)配置、認(rèn)證等)帮碰。我們可以把父類的方法定義成final相味,同時(shí)將內(nèi)部可以繼承的部分剝離出來,供子類繼承重寫收毫。下面通過一段代碼演示:

class Parent {
   final func method1() {
       //權(quán)限驗(yàn)證(必須執(zhí)行)
       //.....
        
       method2()
        
       //下面是日志記錄(必須執(zhí)行)
       //..........
   }
    
   func method2(){
       //父類的實(shí)現(xiàn)
       //......
   }
}

class Child : Parent {
   //只能重寫父類的method2方法攻走,不能重寫method1方法
   override func method2() {
       //子類的實(shí)現(xiàn)
       //......
   }
}

indirect

指明在枚舉類型中,存在成員使用相同枚舉類型的實(shí)例作為關(guān)聯(lián)值的情況此再。

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

指明屬性的初始值昔搂,直到第一次被使用時(shí),才進(jìn)行初始化输拇。

class Person  
{  
    lazy var personalityTraits = {  
        //昂貴的數(shù)據(jù)庫開銷  
        return ["Nice", "Funny"]  
    }()  
}
let aPerson = Person()  
aPerson.personalityTraits //當(dāng) personalityTraits 首次被訪問時(shí)摘符,數(shù)據(jù)庫才開始工作

mutating

在Swift中,包含三種類型(type): structure,enumeration,class
其中structure和enumeration是值類型(value type),class是引用類型(reference type)
Swift中protocol的功能比OC中強(qiáng)大很多策吠,不僅能再class中實(shí)現(xiàn)逛裤,同時(shí)也適用于struct、enum猴抹。但是struct带族、enum都是值類型,每個(gè)值都是有默認(rèn)的蟀给,所以在實(shí)例方法中不能改變蝙砌,因此就要用mutating關(guān)鍵字,這個(gè)關(guān)鍵字可以讓在此方法中值的改變跋理,會(huì)返回到原始結(jié)構(gòu)里邊

protocol Vehicle {
    var numberOfWheels: Int {get}
    var color: UIColor {get set}
    mutating func changeColor()
}

struct MyCar: Vehicle {
    let numberOfWheels = 4
    var color = UIColor.blue
    mutating func changeColor() {
        color = .red
    }
}

subscript

  • 下標(biāo)(subscript)在數(shù)組和字典中使用择克,但是你可以給任何類型(枚舉,結(jié)構(gòu)體前普,類)增加 下標(biāo)subscript 的功能肚邢;
  • subscript的語法類似實(shí)例方法、計(jì)算屬性拭卿,其本質(zhì)就是方法骡湖;
struct Person {
    var age = 0
    var no  = 0
    subscript(index: Int) -> Int {
        set {
            if index == 0 {
                age = newValue
            } else {
                no = newValue
            }
        }
        get {
            if index == 0 {
                return age
            } else {
                return no
            }
        }
    }
}

var p = Person()
p[0] = 10
p[1] = 20

print(p.age)  // 10
print(p[0])   // 10

print(p.no)  // 20
print(p[1])  // 20
  • subscript 的返回值類型決定了:
    1.get 方法的返回值類型;
    2.set 方法中 newValue 的類型记劈;
  • subscript 可以接受多個(gè)參數(shù)勺鸦,并且是任意類型;
  • subscript 可以沒有 set 方法目木,但必須要有 get 方法换途;
  • 如果只有 get 方法懊渡,可以省略;
struct Person {
    var age = 30

    subscript(index: Int) -> Int {
        if index == 0 {
            return age
        } else {
            return age * 2
        }
    }
}

var p = Person()
print(p[0])  // 30
print(p[1])  // 60

nonmutating

nonmutating關(guān)鍵字军拟,一般配合set使用剃执。如

protocol Settings {
    subscript(key: String) -> AnyObject? { get nonmutating set }
}

它告訴編譯器不會(huì)修改實(shí)例內(nèi)部的值,也就是set時(shí)懈息,不會(huì)改變?nèi)魏纹渌淖兞俊?/p>

struct Test2 {
    
    var b: Int {
        get {
            return  2
        }
        nonmutating set {
            print("\(newValue)")
        }
    }
}

let t = Test2()
t.b = 3
print(t.b)

optional

用于指明協(xié)議中的可選方法肾档。遵守該協(xié)議的實(shí)體類可以不實(shí)現(xiàn)這個(gè)方法。

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

class Person : Foo  
{  
    func requiredFunction()  
    {  
        print("Conformance is now valid")  
    }  
}

override

指明子類會(huì)提供自定義實(shí)現(xiàn)辫继,覆蓋父類的實(shí)例方法怒见、類型方法、實(shí)例屬性姑宽、類型屬性遣耍、下標(biāo)。如果沒有實(shí)現(xiàn)炮车,則會(huì)直接繼承自父類舵变。

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!

unowned && weak

  • weak:弱引用對(duì)象的引用計(jì)數(shù)不會(huì)+1, 必須為可選類型變量
    在聲明弱引用對(duì)象是必須用var關(guān)鍵字, 不能用let.
    因?yàn)槿跻米兞吭跊]有被強(qiáng)引用的條件下會(huì)變?yōu)閚il, 而let常量在運(yùn)行的時(shí)候不能被改變.
class XDTest {
    //會(huì)報(bào)錯(cuò)
    weak let tentacle = Tentacle() //let is a constant! All weak variables MUST be mutable.
}
  • unowned:相當(dāng)于__unsafe_unretained, 不安全. 必須為非可選類型.
    unowned引用是non-zeroing(非零的), 在ARC銷毀內(nèi)存后,不會(huì)被賦為nil, 這表示著當(dāng)一個(gè)對(duì)象被銷毀時(shí), 它指引的對(duì)象不會(huì)清零. 也就是說使用unowned引用在某些情況下可能導(dǎo)致dangling pointers(野指針). 所以在訪問無主引用的時(shí)候瘦穆,要確保其引用正確纪隙,不然會(huì)引起內(nèi)存崩潰.

throw && rethrow

  • throws的使用很簡單,只需要在可能出現(xiàn)異常的函數(shù)或者方法后面添加throws扛或。
    經(jīng)過這個(gè)關(guān)鍵字修飾的函數(shù)绵咱,在調(diào)用的時(shí)候,需要程序員加上do-catch來調(diào)用.

  • rethrows是異常往上傳遞的關(guān)鍵字熙兔。上面說了throws用在可能出現(xiàn)異常的函數(shù)或者方法中麸拄,而rethrows針對(duì)的不是函數(shù)或者方法的本身,而是它攜帶的閉包類型的參數(shù)黔姜,當(dāng)它的閉包類型的參數(shù)throws的時(shí)候,我們要使用rethrows繼續(xù)將這個(gè)異常往上傳遞蒂萎, 直到被調(diào)用者使用到秆吵。這相比throws多一個(gè)傳遞的環(huán)節(jié)。

@dynamicMemberLookup

這個(gè)特性中文可以叫動(dòng)態(tài)查找成員五慈。在使用@dynamicMemberLookup標(biāo)記了對(duì)象后(對(duì)象纳寂、結(jié)構(gòu)體、枚舉泻拦、protocol)毙芜,實(shí)現(xiàn)了subscript(dynamicMember member: String)方法后我們就可以訪問到對(duì)象不存在的屬性。如果訪問到的屬性不存在争拐,就會(huì)調(diào)用到實(shí)現(xiàn)的 subscript(dynamicMember member: String)方法腋粥,key 作為 member 傳入這個(gè)方法。

@dynamicMemberLookup
struct Person {
   subscript(dynamicMember member: String) -> String {
       let properties = ["nickname": "Zhuo", "city": "Hangzhou"]
       return properties[member, default: "undefined"]
   }
}

//執(zhí)行以下代碼
let p = Person()
print(p.city)
print(p.nickname)
print(p.name)
image.png

@autoclosure,他可以讓我們的表達(dá)式自動(dòng)封裝成一個(gè)閉包隘冲。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末闹瞧,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子展辞,更是在濱河造成了極大的恐慌奥邮,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件罗珍,死亡現(xiàn)場離奇詭異洽腺,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)覆旱,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門蘸朋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人通殃,你說我怎么就攤上這事度液。” “怎么了画舌?”我有些...
    開封第一講書人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵堕担,是天一觀的道長。 經(jīng)常有香客問我曲聂,道長霹购,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任朋腋,我火速辦了婚禮齐疙,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘旭咽。我一直安慰自己贞奋,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開白布穷绵。 她就那樣靜靜地躺著轿塔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪仲墨。 梳的紋絲不亂的頭發(fā)上勾缭,一...
    開封第一講書人閱讀 51,292評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音目养,去河邊找鬼俩由。 笑死,一個(gè)胖子當(dāng)著我的面吹牛癌蚁,可吹牛的內(nèi)容都是我干的幻梯。 我是一名探鬼主播兜畸,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼礼旅!你這毒婦竟也來了膳叨?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤痘系,失蹤者是張志新(化名)和其女友劉穎菲嘴,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體汰翠,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡龄坪,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了复唤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片健田。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖佛纫,靈堂內(nèi)的尸體忽然破棺而出妓局,到底是詐尸還是另有隱情,我是刑警寧澤呈宇,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布好爬,位于F島的核電站,受9級(jí)特大地震影響甥啄,放射性物質(zhì)發(fā)生泄漏存炮。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一蜈漓、第九天 我趴在偏房一處隱蔽的房頂上張望穆桂。 院中可真熱鬧,春花似錦融虽、人聲如沸享完。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽驼侠。三九已至,卻和暖如春谆吴,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背苛预。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來泰國打工句狼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人热某。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓腻菇,卻偏偏與公主長得像胳螟,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子筹吐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Swift官方文檔的詞匯結(jié)構(gòu)中, 有非常多的關(guān)鍵字, 它們被用于聲明中糖耸、語句中、表達(dá)式中丘薛、類中嘉竟、模式中, 還有以數(shù)...
    小宇宙_fly閱讀 770評(píng)論 0 3
  • 作者:Jordan Morgan,原文鏈接洋侨,原文日期:2017-02-11 譯者:鄭一一舍扰;校對(duì):numbbbbb,...
    iOS亮子閱讀 642評(píng)論 0 1
  • 有句話之前我提過希坚,今天還想再說一次边苹。那就是打鐵還需自身硬。對(duì)于自身能力的嚴(yán)格要求裁僧,可以幫助實(shí)現(xiàn)我們所有夢寐以求的東...
    蘋果上的小豌豆閱讀 2,156評(píng)論 0 7
  • ? ! ? Swift是一個(gè)強(qiáng)類型語言个束,它希望在編譯器做更多的安全檢查,所以引入了類型判斷聊疲。而在類型判斷上如果...
    HuangJn閱讀 794評(píng)論 0 1
  • 2017年3月30日第一次更新 一.用作聲明的關(guān)鍵字: class茬底、deinit、enum售睹、extension桩警、f...
    RaInVis閱讀 521評(píng)論 0 2