Swift 列舉內存管理與異常處理具體代碼

1. Swift 內存銷毀時機

// Swift5 內存銷毀時機
// 引用類型的內存銷毀時機
class ClassDemo {
    var a = "value a"
    deinit {
        // 實例被釋放
        print("deinit class a")
    }
}

// 可空類型
var ins1: ClassDemo? = ClassDemo()
var ins2 = ins1
var ins3 = ins2

ins1 = nil // 取消 ins1 引用
ins2 = nil // 取消 ins2 引用
print(String(describing: ins3?.a)) // 此處 ins3 引用的實例依然在,Optional("value a")

// 對實例引用被全部取消,ClassA 實例此處才銷毀
ins3 = nil // deinit class a

2. Swift 單向引用

// Swift5 單向引用
class ClassA {
    
    deinit {
        print("deinit ClassA")
    }
    
    func foo() {
        print("func foo in ClassA")
    }
}

class ClassB {
    // 此處引用 ClassA 的實例
    var ins: ClassA?
    
    init(ins: ClassA?) {
        self.ins = ins
    }
    
    deinit {
        print("deinit ClassB")
    }
}

var clzA: ClassA? = ClassA()
var clzB: ClassB? = ClassB(ins: clzA)

// 此處 clzA 所引用的內存並未釋放
clzA = nil
// 依然可以調用 clzB 中的 clzA 實例的 foo 方法
clzB?.ins?.foo() // func foo in ClassA
// 此時 ClassB 實例被釋放,不再有引用指向 ClassA 隨即所占內存也被釋放
clzB = nil // deinit ClassB \n deinit ClassA

3. Swift 循環引用

// Swift5 循環引用
class ClassC {
    var insD: ClassD?
    
    deinit {
        print("deinit ClassC")
    }
    
    func foo() {
        print("func foo in ClassC")
    }
}

class ClassD {
    // 此處引用 ClassC 的實例
    var insC: ClassC?
    
    init(ins: ClassC?) {
        self.insC = ins
    }
    
    deinit {
        print("deinit ClassD")
    }
}

var clzC: ClassC? = ClassC()
var clzD: ClassD? = ClassD(ins: clzC)

clzC?.insD = clzD

// 此處 clzC 所引用的內存並未釋放,對應實例被 clzD 的 insC 引用
clzC = nil
// 依然可以調用 clzD 中的 insC 實例的 foo 方法
clzD?.insC?.foo() // func foo in ClassC
// 此時 clzD 的實例依然被 clzC 的 insD 引用,clzC 和 clzD 實例都未被釋放
clzD = nil

4. Swift 弱引用 解決 循環引用 問題

// Swift5 使用 弱引用 解決 循環引用
class ClassE {
    // 弱引用 weak
    weak var insF: ClassF?
    
    deinit {
        print("deinit ClassE")
    }
    
    func foo() {
        print("func foo in ClassE")
    }
}

class ClassF {
    // 此處引用 ClassE 的實例
    var insE: ClassE?
    
    init(ins: ClassE?) {
        self.insE = ins
    }
    
    deinit {
        print("deinit ClassF")
    }
}

var clzE: ClassE? = ClassE()
var clzF: ClassF? = ClassF(ins: clzE)

clzE?.insF = clzF

// 此處 clzE 所引用的內存並未釋放,對應實例被 clzF 的 insE 引用
clzE = nil
// 依然可以調用 clzF 中的 insE 實例的 foo 方法
clzF?.insE?.foo() // func foo in ClassE
// 此時 clzF 的實例被 clzE 的 insF 弱引用,會被銷毀,clzE 和 clzF 實例都能被釋放
clzF = nil // deinit ClassF \n deinit ClassE

5. Swift 無主引用,針對類型為非 Optional

// Swift5 無主引用,針對類型為非 Optional
class ClassG {
    // 無主引用 unowned 假定屬性不為 nil
    unowned var insH: ClassH
    
    init(ins: ClassH) {
        self.insH = ins
    }
    func foo() {
        print("func foo in ClassG")
    }
    deinit {
        print("deinit ClassG")
    }
}

class ClassH {
    // 此處引用 ClassE 的實例
    var insG: ClassG?
    
    deinit {
        print("deinit ClassH")
    }

}
var clzH: ClassH? = ClassH()
var clzG: ClassG? = ClassG(ins: clzH!)


clzH?.insG = clzG

// 此處 clzG 所引用的內存並未釋放,對應實例被 clzH 的 insG 引用
clzG = nil
// 依然可以調用 clzH 中的 insG 實例的 foo 方法
clzH?.insG?.foo() // func foo in ClassG
// 此時 clzH 的實例被 clzG 的 insH 無主引用,會被銷毀,clzG 和 clzH 實例都能被釋放
clzH = nil // deinit ClassH \n deinit ClassG

6. Swift 閉包產生的循環引用

// Swift5 閉包產生的循環引用
class ClassJ {
    var field = "field j"
    
    lazy var closure: () -> Void = {
        print(self.field)
    }
    
    deinit {
        print("deinit ClassJ")
    }
}

var objJ: ClassJ? = ClassJ()
objJ?.closure()
// 因為閉包引用瞭類的成員屬性,導致實例無法釋放,進而導致閉包無法釋放,產生循環引用
objJ = nil // 此處並沒有打印 deinit 中信息

7. Swift 解決閉包產生的循環引用

// Swift5 解決閉包產生的循環引用
class ClassK {
    var field = "field k"
    
    lazy var closure: () -> Void = {
        // 使用捕獲列表對 self 進行無主引用的轉換
        [unowned self] () -> Void in
        print(self.field)
    }
    
    deinit {
        print("deinit ClassK")
    }
}

var objK: ClassK? = ClassK()
objK?.closure()
objK = nil // deinit ClassK

8. Swift 自定義異常類型

// Swift5 自定義異常類型
enum CustomError: Error {
    case ErrorOne
    case ErrorTwo
    case ErrorThree
}

print("error")
//throw CustomError.ErrorOne // 拋出的異常未捕獲會終止,不會打印 complete
print("complete")

9. Swift do-catch 捕獲異常,try 執行會拋異常的函數

// Swift5 使用 do-catch 捕獲異常,try 執行會拋異常的函數
// 通過函數拋出異常
func funcError() throws -> String {
    throw CustomError.ErrorTwo
}

// 使用 do-catch 捕獲異常
do {
    // 使用 try 執行可能會拋出異常的函數
    try funcError()
} catch CustomError.ErrorOne {
    print("ErrorOne")
} catch CustomError.ErrorTwo {
    print("ErrorTwo")
} catch CustomError.ErrorThree {
    print("ErrorThree")
}

// 使用 try? 將函數執行的結果映射為 Optional 類型
let result = try? funcError()
if (result == nil) {
    print("exec failed")
}

// try! 強行終止異常的傳遞,如果發生異常,則程序中斷
// try! funcError()

10. Swift 函數延時執行結構

// Swift5 函數延時執行結構:避免在拋異常的時候,保證某些必須的代碼塊要執行,如釋放資源
func lazyFunc() throws -> Void {

    defer {
        // 函數結束時會得到執行
        print("lazy part of func")
    }
    
    print("exec lazyFunc")
    throw CustomError.ErrorThree
}

// exec lazyFunc
// lazy part of func
try? lazyFunc()

GitHub 源碼:Reference&Error.playground

到此這篇關於Swift 列舉內存管理與異常處理具體代碼的文章就介紹到這瞭,更多相關Swift 內存管理與異常處理內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!

推薦閱讀: