IOS中解決ARC類執行個體間循環參考(Swfit)

來源:互聯網
上載者:User

標籤:ios   arc   循環參考   swfit   

原創Blog,轉載請註明出處
http://blog.csdn.net/column/details/swfitexperience.html
備忘:本文代碼和圖片主要來自於官方文檔
不熟悉ARC的同學可以看看前一篇關於ARC的簡述,這個是我的Swfit教程專欄
http://blog.csdn.net/column/details/swift-hwc.html
一、幾個用到的關鍵概念

弱引用(weak):不會增加自動引用計數,必須為可選類型變數,因為弱引用在引用計數為0的時候,會自動賦為nil。在swfit中,可以賦值為nil的為可選類型
無主引用(unonwed):不會增加自動引用計數,必須為非可選類型。在ARC銷毀記憶體後,不會被賦為nil,所以在訪問無主引用的時候,要確保其引用正確,不然會引起記憶體崩潰。
隱式解析可選類型:在初始的時候可以為nil,但是第一次賦值以後便會一直有值。文法是在變數後面加上驚嘆號(例如var name:String!)。使用該類型只需要正常調用,不需要像可選類型那樣做判斷。


二、類執行個體之間的循環參考
1、執行個體A可選包含執行個體B的引用,執行個體B可選包含執行個體A的引用-用弱引用來解決

舉例:
下面兩個類,公寓不一定有住戶,住戶也不一定在公寓裡
反面教材:兩個都是強引用會導致循環參考
class Person {let name: Stringinit(name: String) { self.name = name }var apartment: Apartment?deinit { println("\(name) is being deinitialized") }}class Apartment {let number: Intinit(number: Int) { self.number = number }var tenant: Person?deinit { println("Apartment #\(number) is being deinitialized") }}var john: Person?var number73: Apartment?john = Person(name: "John Appleseed")number73 = Apartment(number: 73)john!.apartment = number73number73!.tenant = john
然後,這樣就形成了循環參考(此時兩個執行個體引用計數都為2),1.1


然後將兩個強引用斷開後,本應該釋放的記憶體
john = nilnumber73 = nil
這時候記憶體1.2


由於兩個執行個體相互存在強引用(引用計數一直為1),所以這塊記憶體一直沒辦法釋放。
解決方案,採用弱引用,
class Person {let name: Stringinit(name: String) { self.name = name }var apartment: Apartment?deinit { println("\(name) is being deinitialized") }}class Apartment {let number: Intinit(number: Int) { self.number = number }weak var tenant: Person?deinit { println("Apartment #\(number) is being deinitialized") }}var john: Person?var number73: Apartment?john = Person(name: "John Appleseed")number73 = Apartment(number: 73)john!.apartment = number73number73!.tenant = john
此時,記憶體配置圖1.3,此時Person執行個體引用計數為1,Apartment執行個體引用計數為2


然後將兩個強引用斷開後,
john = nilnumber73 = nil
記憶體1.4


這時候,Person引用計數為0,Apartment執行個體引用計數為1
由於Person執行個體引用計數為0,Person記憶體被釋放,導致Apartment執行個體引用計數為0,記憶體被釋放

2、執行個體A可選包含執行個體B,執行個體B一定包含執行個體A-用無主引用解決
舉例
使用者可能沒有信用卡,但是信用卡一定會有使用者。由於信用卡一定有使用者,所以不是可選類型,不能用弱引用,swift中提供的無主引用是簡單便捷的解決方案。
class Customer {    let name: String    var card: CreditCard?    init(name: String) {        self.name = name    }    deinit { println("\(name) is being deinitialized") }}class CreditCard {    let number: Int    unowned let customer: Customer    init(number: Int, customer: Customer) {        self.number = number        self.customer = customer    }    deinit { println("Card #\(number) is being deinitialized") }}var john: Customer?john = Customer(name: "John Appleseed")john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)


這樣記憶體2.1,此時使用者執行個體引用為1,信用卡執行個體引用為1

使用者登出後,
join = nil
那麼使用者執行個體引用計數為0,導致使用者執行個體被釋放,導致信用卡執行個體引用為0,記憶體釋放,2.2


看到這,聰明的同學會問了:由於Customer中的信用卡是可選的,我把它設為弱引用不能解決這個問題嗎?
舉例
class Customer {    let name: String    weak var card: CreditCard?    init(name: String) {        self.name = name    }    deinit { println("\(name) is being deinitialized") }}class CreditCard {    let number: Int    let customer: Customer    init(number: Int, customer: Customer) {        self.number = number        self.customer = customer    }    deinit { println("Card #\(number) is being deinitialized") }}var john: Customer?john = Customer(name: "John Appleseed")john!.card = CreditCard(number: 1234_5678_9012_3456, customer: john!)


此時的記憶體模型


可以看到問題了吧?由於card只有一個弱引用,也就是引用計數為0,這樣的對象在建立之後就會被釋放掉。所以,沒辦法實現上述功能了。

3、A一定包含B,B一定包含A - 用隱式解析+無主引用解決
舉例:國家一定包含首都,首都也一定在一個國家裡
class Country {let name: Stringlet capitalCity: City!init(name: String, capitalName: String) {self.name = nameself.capitalCity = City(name: capitalName, country: self)}}class City {let name: Stringunowned let country: Countryinit(name: String, country: Country) {self.name = nameself.country = country}}

這裡,Country的建構函式裡,City要調用self,而只有Country的執行個體完全初始化結束後才能調用self。所以,capitialCity設為隱式可選類型,讓他預設為nil,這樣構造過程的第一階段就可以不包括captialCity,就可以把self賦值給Country賦值給capittalCity了。
想詳細看看構造過程的兩個階段,參照我之前寫的構造過程文章,還不懂的話請留言。
這樣設計的意義是:可以通過一條構造與巨還構造國家和首都兩個執行個體,並且可以不用可選解析的方式來訪問首都執行個體。
var country = Country(name: "Canada", capitalName: "Ottawa")println("\(country.name)'s capital city is called \(country.capitalCity.name)")

IOS中解決ARC類執行個體間循環參考(Swfit)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.