Swift的內存管理

BenTucker 7年前發布 | 20K 次閱讀 Swift Apple Swift開發

LLVM編譯器的好:Swift的內存管理除了要注意引用循環之外,幾乎全部被LLVM編譯器包攬,不需要開發人員操心。

引用循環問題是什么

Swift 使用 ARC(自動引用計數)的方法為引用類型管理內存。

在 Swift 中,當聲明引用類型的變量并將對象負值給他時,相當于創建了對該對象的強引用,引用該對象的對象的引用計數將加1。如果兩個對象相互強引用,將導致引用循環。引用循環一旦出現,相關的對象將無法釋放,從而產生內存泄漏。

引用循環問題出現的場景與解決辦法

Swift中類對象和閉包都是通過引用進行傳值,所以以下場景會出現引用循環:

類對象相互強引用

兩個對象彼此引用對方時,形成引用循環。

class Letter { 
    let addressedTo: String 
    var mailbox : MailBox? 

    init( addressedTo: String) {
        self. addressedTo = addressedTo 
    } 

    deinit { 
        printl(" The letter addressed to \(addressedTo) is being discarded") 
    } 
}

class MailBox { 
    let poNumber: Int 
    var letter : Letter? 

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

    deinit { 
        print(" P.O Box \(poNumber is going away)") 
    } 
}

Letter 類中強引用了 MailBox 類對象,MailBox 類中又強引用了 Letter 類對象形成引用循環。

解決辦法:聲明對象時加入 weak 關鍵字(弱引用)可以解除強引用。比如將 letter 對象聲明為 weak 時,mailbox 對象的引用計數不會加1,從而解除引用循環。一般將邏輯上屬于另一對象的對象聲明為弱對象。如:

weak var letter : Letter?

閉包中引用包含自身的對象

閉包中引用包含自身的對象也會造成引用循環。

class MailChecker { 
    let mailbox: MailBox 
    let letter: Letter 

    lazy var whoseMail: () -> String = { 
        return "Letter is addressed to \(self. letter.addressedTo)"
    }

    init(name: String) { 
        self. mailbox = MailBox( poNumber: 311) 
        self. letter = Letter( addressedTo: name) 
    } 

    deinit { 
        println(" class is being deintialized")
    }
}

示例代碼中 whoseMail 的閉包中使用 self 引用了包含自身的 MailChecker 對象,此時該閉包擁有 MailChecker 對象,而 MailChecker 對象又擁有該閉包,導致引用循環。

解決辦法:此時可以添加 [unowned self] 讓 Swift 知道不應保留 self 對象,從而解除引用循環。將閉包改為:

lazy var whoseMail: () -> String = { [unowned self] in
    return "Letter is addressed to \(self. letter.addressedTo)"
}

注:代碼均取自 Boisy G. Pitre《Swift基礎教程》

 

來自:http://www.jianshu.com/p/5156d2b2fc4e

 

 本文由用戶 BenTucker 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!