[英]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
的首都,則此方法有效。 但是,如果我想創建一個城市會怎樣?
這將創建一個運行時異常,因為沒有引用City
的Country
引用,因為它是一個未擁有的變量:
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).
我如何允許這樣的事情而不創建強大的參考周期?
有兩種典型的解決方案:
如果您想主要與城市打交道,請反轉關系,以使City
對Country
有很強的引用,而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.