簡體   English   中英

兩個弱變量在Swift中相互引用?

[英]Two weak variables referencing each other in Swift?

我今天再次嘗試嘗試理解Swift中的保留周期和弱引用。 通過閱讀文檔 ,我看到了以下代碼示例,其中一個引用變量被標記為weak以防止保留周期:

class Person {
    let name: String
    init(name: String) { self.name = name }
    var apartment: Apartment? 
    deinit { print("\(name) is being deinitialized") }
}

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    weak var tenant: Person?             // <---- This var is marked as 'weak'
    deinit { print("Apartment \(unit) is being deinitialized") }
}

var john: Person?
var unit4A: Apartment?

john = Person(name: "John Appleseed")
unit4A = Apartment(unit: "4A")

john!.apartment = unit4A
unit4A!.tenant = john

john = nil // prints "John Appleseed is being deinitialized"
unit4A = nil // prints "Apartment 4A is being deinitialized"

讓變量變弱都有問題嗎? 也就是說,在Person類中,我可以將apartment變量更改為弱,以便我擁有

class Person {
    // ...
    weak var apartment: Apartment?  // added 'weak'
    // ...
}

class Apartment {
    // ...
    weak var tenant: Person?
    // ...
}

其中有兩個相互引用的弱變量。

我在游樂場測試了它似乎工作正常,但有沒有強烈的理由不這樣做? 在這種情況下似乎沒有自然的親子關系。

你可以做到這一點。 唯一的副作用是你需要確保其他東西保留了人和公寓。 在原始代碼中,您只需要保留人員,公寓(與人相關)將保留給您。

嚴格來說,當公寓被拆除時人們沒有被殺死,當人們死亡時公寓沒有被拆除,因此這種情況下的弱參考是有道理的。 通常最好考慮您想要的關系和所有權模型,然后決定如何實現這一目標。

為了增加接受的答案,這里是一個演示行為的具體例子。

試試這是一個游樂場:

class Person {
    let name: String
    init(name: String) { self.name = name }
    weak var apartment: Apartment?
    deinit { print("\(name) is being deinitialized") }
}

class Apartment {
    let unit: String
    init(unit: String) { self.unit = unit }
    weak var tenant: Person?             // <---- This var is marked as 'weak'
    deinit { print("Apartment \(unit) is being deinitialized") }
}

class Test {
    var person: Person
    init() {
        person = Person(name: "Fred")
        let unit2B = Apartment(unit: "2B")
        person.apartment = unit2B
        unit2B.tenant = person
        print(person.apartment!.unit)
    }

    func test() {
        print(person.apartment!.unit)
    }
}

func go() {
    let t = Test()
    t.test()  // crashes here!
}

go()

在類Testinit時,已創建的公寓由本地變量unit2B保留。 init完成時,公寓將被釋放,因為不再有任何強引用,因此當調用test時程序崩潰,因為person.apartment現在nil

如果從class Person weak var apartment刪除weak ,則此示例不會崩潰,因為在init創建的單元由類屬性person保留的person保留。

修復示例的另一種方法是使unit2B成為class Test的屬性。 然后公寓將有一個強大的參考保持它,所以unit2B將不會在init后解除分配。

如果從class Person weak var apartmentclass Apartment weak var tenant中刪除weak ,則該示例不會崩潰,但是由於兩個保持強大的對象所創建的保留周期, PersonApartment都不會被釋放相互引用。

您的問題沒有提供足夠的信息供我們回答。 您需要退一步研究iOS內存管理。

核心概念是對象所有權。 創建對象並在強變量中存儲指向它的指針時,系統會增加該對象的保留計數。 當變量超出范圍或將nil存儲到其中時,系統會減少保留計數。 當保留計數降至零時,將取消分配對象。

為了使對象繼續存在,您需要至少有一個強引用。 如果不這樣做,它將被取消分配。

弱指針不是擁有引用。

如果對象的唯一引用是弱引用,則可能會立即釋放它。 弱參考是特殊的; 當對象被釋放時,編譯器將它們清零。 這意味着如果您嘗試向保存在弱變量中的對象發送消息,則不會崩潰。 如果已取消分配,則指針將更改為nil,並且將忽略該消息。

編輯

正如@vacawama所指出的,向nil對象發送消息是Objective-C的做事方式。 (我最近一直在為Objective-C的客戶全職工作,所以這最近往往是我的心態。問題是關於Swift的。)

在Swift中,您使用可選鏈接,語法如下:

object?.method().

使用此Swift語法,如果object為nil,則跳過方法調用。

很重要:

如果你有2個對象,每個對象都有弱引用,那很好,但是你的程序中的其他地方你需要對兩個對象都有強烈的(擁有)引用,否則它們將被釋放。

非常重要:

如果你有2個對象具有強引用,你就創建了一個“保留周期”,除非你將來某個時候忽略其中一個指針,否則這些對象永遠不會被釋放。 如果您有2個(或更多)對象具有強引用,但您沒有對這些對象的任何其他引用,則會導致內存泄漏。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM