簡體   English   中英

Swift中強大的參考周期

[英]Strong reference cycles in Swift

我正在看《 The Swift Programming Language》一書中“ Unown References and Impliclyly Unwrapped Optional Properties”部分中的示例。

他們的示例代碼是

class Country {
    let name: String
    let capitalCity: City!
    init(name: String, capitalName: String) {
        self.name = name
        self.capitalCity = City(name: capitalName, country: self)
    }
}

class City {
    let name: String
    unowned let country: Country
    init(name: String, country: Country) {
        self.name = name
        self.country = country
    }
}

如果我只想與國家打交道,並且“ City類型的唯一目的是成為一個Country的首都,則此方法有效。 但是,如果我想創建一個城市會怎樣?

這將創建一個運行時異常,因為沒有引用CityCountry引用,因為它是一個未擁有的變量:

var chicago = City(name:"Chicago", country: Country(name: "USA", capitalName: "Washington DC"))
chicago.country.name // Playground execution failed: error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=EXC_I386_GPFLT).

我如何允許這樣的事情而不創建強大的參考周期?

有兩種典型的解決方案:

  • 如果您想主要與城市打交道,請反轉關系,以使CityCountry有很強的引用,而Country指向一個無主實例。

  • 如果要將城市和國家作為互相交叉引用的主要對象,請將所有城市和國家放入集合(或擁有它們的其他形式的商店)中,並使這兩個引用均變弱。 這樣,他們就不會彼此擁有,而且您也沒有周期。

避免保留周期的最佳方法是考慮誰擁有每個對象。 對象可以彼此擁有,但是應該是清晰的層次結構(即樹)。 如果您的連接在層次結構中橫向排列或向上排列,請將其設置為弱連接或無連接。

解決方案一是向上的情況,解決方案二是側向的情況。

編輯

  • 第三種選擇是,讓Country擁有其所有城市的集合。 我認為在這種簡單情況下最有意義,但這意味着“ Country需要在初始化時創建所有城市,或者有一種添加城市的方法。

這是第二種情況的示例。 它非常復雜,對於這個簡單的案例來說可能太多了,但是它說明了提取一個公共所有者。 如果有很多交叉引用,我通常會使用它。 (請考慮關系數據庫。這些記錄互不擁有。)

class Country {
    let name: String
    weak var capitalCity: City?
    init(name: String) {
        self.name = name
    }
}

class City {
    let name: String
    unowned let country: Country
    init(name: String, country: Country, isCapital: Bool) {
        self.name = name
        self.country = country
        if isCapital {
            country.capitalCity = self
        }
    }
}

class Planet {
    var countries: [Country] = []
    var cities: [City] = []
}

let earth = Planet()

earth.countries = [
    Country(name: "USA"),
    Country(name: "Canada"),
]

earth.cities = [
    City(name: "Washington DC", country: earth.countries[0], isCapital: true),
    City(name: "Chicago", country: earth.countries[0], isCapital: false),
    City(name: "Ottawa", country: earth.countries[1], isCapital: true),
]

在您的示例中,沒有人擁有Country實例。 這意味着它將立即被釋放(釋放)。

var country = Country(name: "USA", capitalName: "Washington DC")
var chicago = City(name:"Chicago", country: country)
chicago.country.name

將解決此問題,因為我們的coutry變量將阻止USA取消分配

如果使用無主引用,則始終必須在其他地方保留強引用。

暫無
暫無

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

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