Swift中强大的参考周期

时间:2014-06-05 14:25:58

标签: swift

我正在查看“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

如果不创建强参考周期,我将如何允许这样的事情?

2 个答案:

答案 0 :(得分:4)

有两种典型的解决方案:

  • 如果您想主要处理城市,请反转关系,以便City强烈引用CountryCountry指向无主实例。< / 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无法取消分配

如果使用无主参考,则必须在其他地方保留强引用。