我正在查看“The Swift Programming Language”一书中“无主引用和隐式解包可选属性”部分的示例。
他们的示例代码是
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
的{{1}}的引用,因为它是一个无主变量:
Country
如果不创建强参考周期,我将如何允许这样的事情?
答案 0 :(得分:4)
有两种典型的解决方案:
如果您想主要处理城市,请反转关系,以便City
强烈引用Country
,Country
指向无主实例。< / p>
如果您希望将城市和国家/地区作为主要对象相互交叉引用,请将所有城市和国家/地区放入集合(或拥有它们的其他形式的商店),并使两个引用都变弱。这样他们就没有彼此拥有,而你没有一个周期。
避免保留周期的最佳方法是考虑谁拥有每个对象。对象可以彼此拥有,但这应该是一个清晰的层次结构(即树)。如果您在层次结构中有侧向和向上连接,请将它们设置为弱或无主。
解决方案一是向上案例,解决方案二是侧向案例。
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), ]
答案 1 :(得分:0)
在您的示例中,没有人拥有Country
实例。这意味着它会立即被释放(释放)。
var country = Country(name: "USA", capitalName: "Washington DC")
var chicago = City(name:"Chicago", country: country)
chicago.country.name
会修复它,因为我们的coutry
变量会使USA
无法取消分配
如果使用无主参考,则必须在其他地方保留强引用。