Swift5.2 拾遺筆記(一)

本文為私人學(xué)習(xí)筆記览濒,僅僅做為記錄使用浦妄,詳情內(nèi)容請查閱 中文官方文檔厨喂。


屬性

  • 屬性包裝器

屬性包裝器在管理如何存儲和定義屬性的代碼之前添加了一個(gè)分隔層。舉個(gè)例子奴烙,如果你想要對屬性進(jìn)行線程安全地存取助被,那你勢必要在所有存取的地方編寫相同的代碼進(jìn)行線程安全管理,是不是非常的麻煩切诀?屬性包裝器則幫你實(shí)現(xiàn)一次編寫揩环,終身復(fù)用的效果。

定義一個(gè)屬性包裝器趾牧,你需要創(chuàng)建一個(gè)具有 warppedValue 屬性的結(jié)構(gòu)體检盼、枚舉或者類。這個(gè) warppedValue 屬性就是包裝器需要的包裝屬性翘单。

定義一個(gè) TwelveOrLess 結(jié)構(gòu)體吨枉,確保包裝器所修飾的屬性存儲的值都是小于或等于 12 的數(shù)字。

@propertyWrapper
struct TwelveOrLess {
    private var number: Int
    init() { self.number = 0 }
    var wrappedValue: Int {
        get { return number }
        set { number = min(newValue, 12) }
    }
}

你現(xiàn)在可以在屬性前面寫上包裝器哄芜,將包裝器作為特性的方式來使用貌亭。

struct SmallRectangle {
    @TwelveOrLess var height: Int
    @TwelveOrLess var width: Int
}

var rectangle = SmallRectangle()
print(rectangle.height)
// 打印 "0"

rectangle.height = 10
print(rectangle.height)
// 打印 "10"

rectangle.height = 24
print(rectangle.height)
// 打印 "12"

上述過程中,當(dāng)你操作 rectangle 的屬性進(jìn)行讀寫時(shí)认臊,都會經(jīng)過包裝器 wrappedValue 屬性的讀寫圃庭。編譯器將會合成包裝器所提供的存儲空間和訪問屬性的代碼。過程就像下面這樣失晴。

struct SmallRectangle {
    private var _height = TwelveOrLess()
    private var _width = TwelveOrLess()
    var height: Int {
        get { return _height.wrappedValue }
        set { _height.wrappedValue = newValue }
    }
    var width: Int {
        get { return _width.wrappedValue }
        set { _width.wrappedValue = newValue }
    }
}
  • 類型屬性

類型屬性存儲的數(shù)據(jù)為共享數(shù)據(jù)剧腻。存儲型類型屬性可以是常量也可以是變量,但是計(jì)算型類型屬性和實(shí)例的計(jì)算型屬性一樣涂屁,只能定義成變量屬性书在。

需要注意的是,由于類型本身并沒有構(gòu)造器拆又,也就無法在初始化過程中為類型屬性賦值儒旬,因此必須給存儲型類型屬性指定默認(rèn)值。存儲型類型屬性是延遲初始化的帖族,它們只有在第一次被訪問時(shí)才被初始化栈源。即使它們被多個(gè)線程同時(shí)訪問,系統(tǒng)也保證智慧對其進(jìn)行一次初始化竖般,并且不需要對其使用 lazy 修飾符甚垦。這種特性也保證了對內(nèi)存的優(yōu)化。

方法

結(jié)構(gòu)體和枚舉能夠定義方法是 Swift 和 OC 的主要區(qū)別之一。

  • mutating 可變方法

和類不同制轰,值類型的結(jié)構(gòu)體和枚舉默認(rèn)情況下前计,其屬性不能夠修改,但是你確實(shí)需要修改時(shí)垃杖,可以為方法添加 可變 mutating 行為男杈。

struct Point {
    var x = 0.0, y = 0.0
    mutating func moveBy(x deltaX: Double, y deltaY: Double) {
        x += deltaX
        y += deltaY
    }
}
  • 類型方法

和 OC 一樣,類型方法屬于類本身调俘。有兩種方式定義類型方法伶棒,func 前添加 staticclass后者允許子類重寫彩库。類型方法位于方法體 {} 中的最前面肤无,作用域?qū)儆谠擃惖姆秶?/p>

  • self 屬性

在實(shí)例方法中,self 屬性指向?qū)嵗旧砗眨憧梢允褂?self 來引用當(dāng)前實(shí)例宛渐,當(dāng)然 Swift 并不推薦使用它,self 的使用場景主要是在實(shí)例方法的某個(gè)參數(shù)名和實(shí)例的屬性名重復(fù)時(shí)眯搭,用 self 區(qū)分參數(shù)還是屬性窥翩,否則,參數(shù)優(yōu)先鳞仙,兩個(gè)都被認(rèn)為是參數(shù)名寇蚊。

struct Point {
    var x = 0.0, y = 0.0
    func isToTheRightOf(x: Double) -> Bool {
        return self.x > x
    }
}

在類型方法中,self 屬性指向類本身棍好,而不是該類型的某個(gè)實(shí)例仗岸。一般來說,在類型方法的方法體中借笙,可以直接通過類型方法的名稱調(diào)用本類中的其他類型方法扒怖,而不需要在方法名稱前面加上類型名,類似的业稼,類型屬性也同樣可以通過名稱直接訪問其他類型屬性姚垃,而不需要前面加上本類的類名。

下標(biāo)

快捷訪問集合盼忌、列表或序列中的元素而不需要使用存取方法,可以定義在類掂墓、結(jié)構(gòu)體和枚舉中谦纱。下標(biāo)不限于一維。

  • subscript
subscript(index: Int) -> Int {
    get {
      // 返回一個(gè)適當(dāng)?shù)?Int 類型的值
    }
    set(newValue) {
      // 執(zhí)行適當(dāng)?shù)馁x值操作
    }
}

示例

struct Collection {
    let data : [Any]
    subscript(index: Int) -> Any? {
        get {
            if index < data.count {
                return data[index]
            } else {
                return nil
            }
        }
    }
}
let cc = Collection(data : ["0","1","2","3"])
print(cc[1] ?? "無")
  • 類型下標(biāo)

類似類型方法君编,通過 staticclass 來定義類型下標(biāo)跨嘉,后者可以重寫。

enum Planet: Int {
    case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
    static subscript(n: Int) -> Planet {
        return Planet(rawValue: n)!
    }
}
let mars = Planet[4]
print(mars)

繼承

繼承和引用特性是區(qū)分類和結(jié)構(gòu)體吃嘿、枚舉的基本特征祠乃。Swift 中的類不需要像 OC 中從一個(gè)通用的 NSObject 基類繼承而來梦重。不繼承其他類的類,稱之為基類亮瓷。

  • 重寫屬性的 Getters 和 Setters

重寫的屬性的限制不變小琴拧,即:可以將一個(gè)繼承來的只讀屬性重寫為一個(gè)讀寫屬性,也可以將讀寫屬性重寫為一個(gè)只讀屬性嘱支。另外蚓胸,如果你在重寫屬性中提供來了setter,那么你一定要提供對應(yīng)的 getter除师,反之沒有限制沛膳。

  • 屬性觀察器

可以通過重寫屬性為一個(gè)繼承來的屬性添加屬性觀察器。這樣一來汛聚,無論被繼承屬性原本是如何實(shí)現(xiàn)的锹安,當(dāng)其屬性值發(fā)生改變時(shí),你就會被通知到倚舀。

無論是存儲類型還是計(jì)算類型的屬性都可以添加屬性觀察器叹哭,但是依舊有限制,那些常量存儲類型或者只讀計(jì)算類型屬性無法添加瞄桨,因?yàn)檫@些值是不可以被改變的话速,為它們設(shè)置 willSetdidSet 是不太恰當(dāng)?shù)牟僮鳎硗庑窘模瑢傩杂^察器和 setter 是不能同時(shí)存在的泊交,因?yàn)?setter 本身就已經(jīng)可以觀察到屬性的變化了。

  • final

final 關(guān)鍵字來限制被重寫柱查、繼承廓俭,這意味著被修飾的屬性、方法或者類都是最終類型唉工。例如:final var研乒、final funcfinal class func 以及 final subscript淋硝。

構(gòu)造過程

設(shè)置實(shí)例存儲屬性的初始值和執(zhí)行其他必須的設(shè)置或構(gòu)造過程雹熬。

你可以在構(gòu)造器中為存儲類屬性設(shè)置初始值,或者在定義屬性時(shí)分配默認(rèn)值谣膳。(這兩種方式是直接設(shè)置的竿报,不會觸發(fā)任何屬性觀察者)

// 構(gòu)造器中設(shè)置初始值
struct Fahrenheit {
    var temperature: Double
    init() {
        temperature = 32.0
    }
}
// 默認(rèn)屬性值
struct Fahrenheit {
    var temperature = 32.0
}
  • 構(gòu)造過程中常量屬性賦值

你可以在構(gòu)造過程中的任意時(shí)間點(diǎn)給常量屬性賦值,只要在構(gòu)造過程結(jié)束時(shí)特設(shè)置成確定的值继谚。一旦常量屬性被賦值烈菌,它將永遠(yuǎn)不可更改。

class SurveyQuestion {
    let text: String
    init(text: String) {
        self.text = text // 常量屬性只能在定義它的類的構(gòu)成過程中修改,不能在其子類中修改
    }
}
  • 默認(rèn)構(gòu)造器

如果結(jié)構(gòu)體或類為所有屬性提供類默認(rèn)值芽世,又沒有提供任何自定義的構(gòu)造器挚赊,那么 Swift 會給這些結(jié)構(gòu)體或類提供一個(gè)默認(rèn)構(gòu)造器。這個(gè)默認(rèn)構(gòu)造器將簡單地創(chuàng)建一個(gè)所有屬性值都設(shè)置為它們默認(rèn)值的實(shí)例济瓢。

  • 結(jié)構(gòu)體的逐一成員構(gòu)造器

結(jié)構(gòu)體如果沒有定義任何自定義構(gòu)造器荠割,它們將自動獲得一個(gè)逐一成員構(gòu)造器(memberwise initializer)。不像默認(rèn)構(gòu)造器葬荷,即使存儲型屬性沒有默認(rèn)值涨共,結(jié)構(gòu)體也能獲得逐一成員構(gòu)造器。

struct Size {
    var width = 0.0, height = 0.0
}
let twoByTwo = Size(width: 2.0, height: 2.0)
  • 值類型的構(gòu)造器代理

構(gòu)造器可以通過調(diào)用其他構(gòu)造器來完成實(shí)例的部分構(gòu)造過程宠漩,這一過程稱為構(gòu)造器代理举反,它能避免過個(gè)構(gòu)造器間的代碼重復(fù)。

struct Size {
    var width = 0.0, height = 0.0
}
struct Point {
    var x = 0.0, y = 0.0
}
struct Rect {
    var origin = Point()
    var size = Size()
    init(origin: Point, size: Size) {
        self.origin = origin
        self.size = size
    }
}

如果你為某個(gè)值類型定了一個(gè)自定義的構(gòu)造器扒吁,你將無法訪問到默認(rèn)構(gòu)造器(如果是結(jié)構(gòu)體火鼻,還將無法反問逐一成員構(gòu)造器)。這種限制避免了在一個(gè)更復(fù)雜的構(gòu)造器中做了額外的重要設(shè)置雕崩,但是使用的人不小心使用自動生成的構(gòu)造器而導(dǎo)致錯(cuò)誤的情況魁索。

如果你仍然希望默認(rèn)構(gòu)造器、逐一成員構(gòu)造器以及自定義構(gòu)造器都能用來創(chuàng)建實(shí)例盼铁,那可以將自定義的構(gòu)造器寫到擴(kuò)展(extension)中粗蔚,而不是寫在值類型的原始定義中。

類的繼承和構(gòu)造過程

類中的所有存儲屬性(包括所有繼承自父類的屬性)都必須在構(gòu)造過程中設(shè)置初始值饶火。

Swift 為類提供類兩種構(gòu)造器來確保實(shí)例中所有存儲屬性都能獲得初始值:指定構(gòu)造器和便利構(gòu)造器鹏控。

每一個(gè)類都必須至少擁有一個(gè)指定的構(gòu)造器。便利構(gòu)造器是類中比較次要的肤寝、輔助性的構(gòu)造器当辐。你可以定義便利構(gòu)造器來調(diào)用同一個(gè)類中的指定構(gòu)造器,并為部分形參提供默認(rèn)值鲤看。你也可以定義便利構(gòu)造器來創(chuàng)建一個(gè)特殊用途或特定輸入值的實(shí)例缘揪。

// 指定構(gòu)造器
init(parameters) {
    statements
}
// 便利構(gòu)造器
convenience init(parameters) {
    statements
}
  • 類構(gòu)造器代理

Swfit 構(gòu)造器之間的代理調(diào)用遵循三條規(guī)則:

  1. 指定構(gòu)造器必須調(diào)用其直接父類的指定構(gòu)造器
  2. 便利構(gòu)造器必須調(diào)用同類中定義的其他構(gòu)造器
  3. 便利構(gòu)造器最后必須調(diào)用指定構(gòu)造器

即:指定構(gòu)造器必須總是向上(父類)代理,便利構(gòu)造器必須總是橫向(同類)代理义桂。

構(gòu)造器代理圖
  • 構(gòu)造器的繼承和重寫

指定構(gòu)造器

當(dāng)你編寫一個(gè)和父類中指定構(gòu)造器相匹配的子類構(gòu)造器時(shí)找筝,你實(shí)際上是在重寫父類的這個(gè)指定構(gòu)造器。因此慷吊,你必須在定義子類構(gòu)造器時(shí)帶上 override 修飾符呻征,該修飾符會讓編譯器去檢查父類中是否有相匹配的指定構(gòu)造器,并驗(yàn)證構(gòu)造器參數(shù)是否被按照預(yù)想中被指定罢浇。

便利構(gòu)造器

如果你編寫了一個(gè)和父類便利構(gòu)造器相匹配的子類構(gòu)造器,由于子類不能直接調(diào)用父類的便利構(gòu)造器(構(gòu)造器代理規(guī)則中指出便利構(gòu)造器需要橫向調(diào)用其他構(gòu)造器),因此嚷闭,嚴(yán)格意義上來講攒岛,你的子類并未對一個(gè)父類構(gòu)造器提供重寫,因此你“重寫”一個(gè)父類便利構(gòu)造器時(shí)胞锰,不需要添加 override 修飾符灾锯。

子類可以在構(gòu)造過程中修改繼承來的變量屬性,但是不能修改繼承來的常量屬性嗅榕。

構(gòu)造器的自動繼承

子類在默認(rèn)情況下不會繼承父類的構(gòu)造器顺饮。但是如果滿足一定的條件,父類構(gòu)造器是可以被自動繼承的凌那,這意味著在許多常見場景你不必重寫父類的構(gòu)造器兼雄,并且可以在安全的情況下以最小的代價(jià)繼承父類的構(gòu)造器。

假如你為子類中引入的所有新屬性都提供了默認(rèn)值帽蝶,下面兩個(gè)規(guī)則將適用:

  1. 如果子類沒有定義任何指定構(gòu)造器赦肋,它將自動繼承父類所有的指定構(gòu)造器
  2. 如果子類提供了所有父類指定構(gòu)造器的實(shí)現(xiàn),它將自動繼承父類所有的便利構(gòu)造器

即使你在子類中添加了更多的便利構(gòu)造器励稳,這兩條規(guī)則仍然適用佃乘。

實(shí)例:

class Food {
    var name: String
    init(name: String) { // 指定構(gòu)造器
        self.name = name
    }
    convenience init() { // 便利構(gòu)造器,需要橫向代理其他構(gòu)造器
        self.init(name: "[Unnamed]")
    }
}

下圖展示了 Food 的構(gòu)造器鏈:

Food 的構(gòu)造器
class RecipeIngredient: Food {
    var quantity: Int
    init(name: String, quantity: Int) {
        self.quantity = quantity
        super.init(name: name)
    }
    override convenience init(name: String) {
        self.init(name: name, quantity: 1)
    }
}

下圖展示了 RecipeIngredient 類的構(gòu)造器鏈:

RecipeIngredient 類的構(gòu)造器

RecipeIngredient 類擁有一個(gè)新的指定構(gòu)造器 init(name: String, quantity: Int) 用來設(shè)置新引入的屬性驹尼,在該構(gòu)造器中趣避,向上代理到父類的指定構(gòu)造器。

RecipeIngredient 也定義類一個(gè)便利構(gòu)造器新翎,init(name: String)程帕,它橫向代理到本類中的指定構(gòu)造器,用來方便地創(chuàng)建 quantity 為 1 的實(shí)例料祠。另外骆捧,該便利構(gòu)造器使用了跟 Food 中指定構(gòu)造器 init(name: String) 相同的形參,因此這個(gè)便利構(gòu)造器重寫了父類的指定構(gòu)造器髓绽,前面需要使用修飾符 override敛苇。

盡管 RecipeIngredient 將父類的指定構(gòu)造器重寫為了便利構(gòu)造器,但是它依然提供了父類所有的指定構(gòu)造器的實(shí)現(xiàn)顺呕,因此枫攀,RecipeIngredient 會自動繼承父類的所有便利構(gòu)造器。在 Food 中株茶,它的一個(gè)便利構(gòu)造器是 init()来涨,這個(gè)會給 RecipeIngredient 繼承。它會代理到 RecipeIngredient 重寫的 init(name: String) 中启盛,接著代理到其他構(gòu)造器中蹦掐。

class ShoppingListItem: RecipeIngredient {
    var purchased = false
    var description: String {
        var output = "\(quantity) x \(name)"
        output += purchased ? " ?" : " ?"
        return output
    }
}

ShoppingListItem 為自己引入的所有屬性提供了默認(rèn)值技羔,并且沒有定義自己的任何構(gòu)造器,因此它將自動繼承所有父類中指定構(gòu)造器和便利構(gòu)造器卧抗。你可以使用其父類中的所有構(gòu)造器來創(chuàng)建實(shí)例藤滥。

下圖展示三個(gè)類的構(gòu)造器鏈:

三個(gè)類的構(gòu)造器
  • 可失敗的構(gòu)造器

所謂的失敗指的是給構(gòu)造器傳入類無效的形參,或者缺少某種所必須的外部資源而導(dǎo)致構(gòu)造失敗的情況社裆。

語法為在 init 關(guān)鍵字后面添加問號(init?)拙绊。

可失敗構(gòu)造器會創(chuàng)建一個(gè)類型為自身類型的可選類型的對象。你通過 return nil 語句來表明可失敗構(gòu)造器在何種情況下應(yīng)該失敗泳秀。

嚴(yán)格來講标沪,Swift 的構(gòu)造器都不支持返回值,因?yàn)闃?gòu)造器本身的作用嗜傅,只是為了確保對象能被正確的構(gòu)造金句。因此你只需要用 return nil 表明可失敗構(gòu)造器構(gòu)造失敗,而不要使用關(guān)鍵字 return 來表明構(gòu)造成功磺陡。

帶原始值的枚舉類型的可失敗構(gòu)造器

此種枚舉類型會自帶一個(gè)可失敗構(gòu)造器 init?(rawValue:)趴梢,該可失敗構(gòu)造器有一個(gè)合適的原始值類型的參數(shù) rawValue 形參,找到匹配的原始值則構(gòu)造成功币他,否則構(gòu)造失敗坞靶。

enum TemperatureUnit: Character {
    case Kelvin = "K", Celsius = "C", Fahrenheit = "F"
}
// 構(gòu)造成功
let fahrenheitUnit = TemperatureUnit(rawValue: "F")
// 構(gòu)造失敗
let unknownUnit = TemperatureUnit(rawValue: "X")

枚舉類型的可失敗構(gòu)造器

你可以通過一個(gè)或者多個(gè)形參的可失敗構(gòu)造器來獲取枚舉類型中特定的枚舉成員。

enum TemperatureUnit {
    case Kelvin, Celsius, Fahrenheit
    init?(symbol: Character) {
        switch symbol {
        case "K":
            self = .Kelvin
        case "C":
            self = .Celsius
        case "F":
            self = .Fahrenheit
        default:
            return nil
        }
    }
}
// 可以正確獲取到枚舉值
let fahrenheitUnit = TemperatureUnit(symbol: "F")
// 將無法匹配蝴悉,構(gòu)造失敗
let unknownUnit = TemperatureUnit(symbol: "X")

構(gòu)成失敗的傳遞

類彰阴、結(jié)構(gòu)體、枚舉的可失敗構(gòu)造器可以橫向代理到它們自己的其他可失敗構(gòu)造器拍冠。類似的尿这,子類的可失敗構(gòu)造器也能向上代理到父類的可失敗構(gòu)造器。

class Product {
    let name: String
    init?(name: String) {
        if name.isEmpty { return nil }
        self.name = name
    }
}
class CartItem: Product {
    let quantity: Int
    init?(name: String, quantity: Int) {
        if quantity < 1 { return nil }
        self.quantity = quantity
        super.init(name: name)
    }
}

Product 類的構(gòu)造條件是 name 不為空庆杜,CartItem 類首先要保證 quantity 的常量存儲類型的屬性的值至少為 1射众,然后向上代理到父類,同樣要保證 name 的值不能為空晃财,兩個(gè)條件不滿足任意一個(gè)都會導(dǎo)致構(gòu)造失敗叨橱。

重寫可失敗構(gòu)造器

你可以在子類中可以重寫父類的可失敗構(gòu)造器。當(dāng)你重寫父類可失敗構(gòu)造器為非可失敗構(gòu)造器時(shí)断盛,需要對父類的可失敗構(gòu)造器進(jìn)行強(qiáng)制解包罗洗。

你可以將可失敗的構(gòu)造器重寫為非可失敗的構(gòu)造器,反過來則不可以

class Document {
    var name: String?
    // 該構(gòu)造器創(chuàng)建了一個(gè) name 屬性的值為 nil 的 document 實(shí)例
    init() {}
    // 該構(gòu)造器創(chuàng)建了一個(gè) name 屬性的值為非空字符串的 document 實(shí)例
    init?(name: String) {
        if name.isEmpty { return nil }
        self.name = name
    }
}

子類將可失敗構(gòu)造器重寫為非可失敗構(gòu)造器:

class AutomaticallyNamedDocument: Document {
    override init() {
        super.init()
        self.name = "[Untitled]"
    }
    override init(name: String) {
        super.init()
        if name.isEmpty {
            self.name = "[Untitled]"
        } else {
            self.name = name
        }
    }
}

class UntitledDocument: Document {
    override init() {
        super.init(name: "[Untitled]")! // 提供默認(rèn)值钢猛,并強(qiáng)制解包
    }
}

必要構(gòu)造器

在類的構(gòu)造器前添加 required 修飾符表明所有該類的子類都必須實(shí)現(xiàn)該構(gòu)造器:

class SomeClass {
    required init() {
        // 構(gòu)造器的實(shí)現(xiàn)代碼
    }
}

在子類重寫父類的必要構(gòu)造器時(shí)伙菜,必須在子類的構(gòu)造器前也添加 required 修飾符,表明該構(gòu)造器要求也應(yīng)用于繼承鏈后面的子類命迈。在重寫父類中必要的指定構(gòu)造器時(shí)贩绕,不需要添加 override 修飾符:

class SomeSubclass: SomeClass {
    required init() {
        // 構(gòu)造器的實(shí)現(xiàn)代碼
    }
}

如果子類繼承的構(gòu)造器能滿足必要構(gòu)造器的要求火的,則無須在子類中顯式提供必要構(gòu)造器的實(shí)現(xiàn)。

通過閉包或函數(shù)設(shè)置屬性的默認(rèn)值

如果某個(gè) 存儲型 屬性的默認(rèn)值需要一些自定義或者設(shè)置丧叽,你可以使用閉包或者全局函數(shù)為其提供定制的默認(rèn)值卫玖。每當(dāng)某個(gè)屬性所在類型的新實(shí)例被構(gòu)造時(shí),那么對應(yīng)的閉包或者函數(shù)會被調(diào)用踊淳,而它們返回值會當(dāng)作默認(rèn)值賦值給這個(gè)屬性。

class SomeClass {
    let someProperty: SomeType = {
        // 在這個(gè)閉包中給 someProperty 創(chuàng)建一個(gè)默認(rèn)值
        // someValue 必須和 SomeType 類型相同
        return someValue
    }()
}

當(dāng) SomeClass 類實(shí)例化時(shí)陕靠, 屬性 someProperty 后的閉包會被調(diào)用迂尝,注意花括號后面的一對小括號,這使用告訴 Swift 立即執(zhí)行此閉包剪芥,如果忽略了這對括號垄开,相當(dāng)于將閉包本身作為值賦值給了屬性,而不是將閉包的返回值賦值給屬性税肪。

如果你使用閉包來初始化屬性溉躲,請記住在閉包執(zhí)行時(shí),實(shí)例的其他部分都還沒有初始化益兄。這意味著你不能在閉包里訪問其他屬性锻梳,即使這些屬性有默認(rèn)值。同樣净捅,你也不能使用隱式的 self 屬性疑枯,或者調(diào)用任何實(shí)例方法。

如果你依舊想使用 self 屬性蛔六,或者調(diào)用其他實(shí)例方法荆永,你可以使用懶加載的形式,通過關(guān)鍵字 lazy 來創(chuàng)建国章。之所以可以使用其他屬性或者實(shí)例方法具钥,是因?yàn)樵搶傩砸呀?jīng)是在類實(shí)例化之后才被調(diào)用,實(shí)例中的屬性都已經(jīng)被初始化液兽,所以可以使用骂删。

lazy var someProperty: SomeType = {
    // 在這個(gè)閉包中給 someProperty 創(chuàng)建一個(gè)默認(rèn)值
    // someValue 必須和 SomeType 類型相同
    // 可以使用 self 等實(shí)例屬性或方法
    return someValue
}()

析構(gòu)過程

析構(gòu)器只適用于類,當(dāng)一個(gè)類的實(shí)例被釋放之前抵碟,析構(gòu)器會被立即調(diào)用桃漾。析構(gòu)器用關(guān)鍵字 deinit 來標(biāo)記。

deinit {
    // 執(zhí)行析構(gòu)過程
}

Swift 會自動釋放不再需要的實(shí)例以釋放資源拟逮。通常不需要你手動去清理撬统,但是,當(dāng)你需要進(jìn)行額外的清理時(shí)敦迄,你則可能需要使用到析構(gòu)器恋追。

析構(gòu)器是被自動調(diào)用的凭迹,你不能主動調(diào)用析構(gòu)器。子類繼承了父類的析構(gòu)器苦囱,并且在子類析構(gòu)器實(shí)現(xiàn)的最后嗅绸,父類的析構(gòu)器依然會被自動調(diào)用。即使子類沒有提供自己的析構(gòu)器撕彤,父類的析構(gòu)器也同樣會被調(diào)用鱼鸠。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市羹铅,隨后出現(xiàn)的幾起案子蚀狰,更是在濱河造成了極大的恐慌,老刑警劉巖职员,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件麻蹋,死亡現(xiàn)場離奇詭異,居然都是意外死亡焊切,警方通過查閱死者的電腦和手機(jī)扮授,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來专肪,“玉大人刹勃,你說我怎么就攤上這事∏K睿” “怎么了深夯?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長诺苹。 經(jīng)常有香客問我咕晋,道長,這世上最難降的妖魔是什么收奔? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任掌呜,我火速辦了婚禮,結(jié)果婚禮上坪哄,老公的妹妹穿的比我還像新娘质蕉。我一直安慰自己,他們只是感情好翩肌,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布模暗。 她就那樣靜靜地躺著,像睡著了一般念祭。 火紅的嫁衣襯著肌膚如雪兑宇。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天粱坤,我揣著相機(jī)與錄音隶糕,去河邊找鬼瓷产。 笑死,一個(gè)胖子當(dāng)著我的面吹牛枚驻,可吹牛的內(nèi)容都是我干的濒旦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼再登,長吁一口氣:“原來是場噩夢啊……” “哼尔邓!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起锉矢,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤铃拇,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后沈撞,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡雕什,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年缠俺,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贷岸。...
    茶點(diǎn)故事閱讀 40,144評論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡壹士,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出偿警,到底是詐尸還是另有隱情躏救,我是刑警寧澤,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布螟蒸,位于F島的核電站盒使,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏七嫌。R本人自食惡果不足惜少办,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望诵原。 院中可真熱鬧英妓,春花似錦、人聲如沸绍赛。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽吗蚌。三九已至腿倚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間褪测,已是汗流浹背猴誊。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工潦刃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人懈叹。 一個(gè)月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓乖杠,卻偏偏與公主長得像,于是被迫代替她去往敵國和親澄成。 傳聞我的和親對象是個(gè)殘疾皇子胧洒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評論 2 355

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