如果我这样创建一个类Agent。它对另一个Agent对象的引用很弱。
class Agent {
weak var partner: Agent?
var name: String
init(name: String) {
self.name = name
}
func makePartner(_ agent: Agent?) {
partner = agent
agent?.partner = self
}
deinit {
print("Deinit for \(name)")
}
}
var sam: Agent? = Agent(name: "Sam")
var bond: Agent? = Agent(name: "Bond")
//sam?.partner = bond //THIS WORKS
//bond?.partner = sam //THIS WORKS
bond?.makePartner(sam) //THIS DOESN'T WORK (deinit called for bond but not sam
sam = nil
bond = nil
如果我通过makePartner方法设置了伙伴关系,然后将两个对象都设置为nil,则只会调用bond的deinit而不是sam。
但是如果我使用
sam?.partner = bond //THIS WORKS
bond?.partner = sam //THIS WORKS
不是调用makePartner,而是调用两个deinit。你能解释为什么会这样吗?通过makePartner方法设置合作伙伴时,哪个参考仍保留给sam。
答案 0 :(得分:0)
这是与Playground相关的问题。在上面的应用程序代码中工作正常。 如果您仍然想在操场上解决此问题, 您可以通过以下方式解决此问题:
bond?.makePartner(sam) - this line
包含以下几行:
bond?.partner = sam
sam?.partner = bond
答案 1 :(得分:0)
此处没有“强参考周期”(以前称为“保留周期”)。您的weak
引用可以防止这种情况。
无法看到两个对象都已被释放的证据,这不是问题代码的结果。这只是一些特殊的游乐场行为。
如果您在应用程序中运行此程序,则可以正常运行。
有趣的是,当我在Xcode 10.2 beta 2游乐场进行测试时,它在那儿也表现正常。
撇开这种分配问题,makePartner
存在两个问题。我敢打赌,您不在乎,这只是对关系薄弱的考验,但如果您确实在意,我想澄清一下问题:
如果“ A”是“ B”的合伙人,但现在我们希望使其成为“ C”的合伙人怎么办。您的代码将使“ A”和“ C”成为彼此的合作伙伴,但是“ B”仍会悬而未决,尽管它与“ A”仍是合作伙伴。
或者如果“ C”以前是“ D”的伙伴,现在又被重新分配为“ A”,那我们真的需要让“ D”知道它不再是“ C”的伙伴。
或者假设“ A”是“ B”的合作伙伴,现在我们要说它没有合作伙伴,即其合作伙伴是nil
。同样,我们需要让“ B”知道其伙伴也是nil
,而不是“ A”。
最后,如您所见,这种“一个人只能与另一个人成为伙伴”这种双重链接的结构有点脆弱,我们真的想确保没有外部代码可以改变任何人的伙伴,但只能通过makePartner
来完成。
因此,您可能会执行以下操作:
class Agent {
weak private(set) var partner: Agent? // give this private setting so no one can mess with this fragile set of relationships
let name: String
init(name: String) {
self.name = name
}
func makePartner(with newPartner: Agent?) { // A was partners with B, but should now be partners with C ...
let oldPartner = self.partner
if let newPartnersOldPartner = newPartner?.partner { // if C is currently partners with D ...
newPartnersOldPartner.partner = nil // ... then D is no longer partnered with anyone.
}
oldPartner?.partner = nil // nor is B any longer partners with anyone.
newPartner?.partner = self // but C is now partners with A ...
partner = newPartner // ... and A is partners with C.
}
deinit {
print("Deinit for \(name)")
}
}
extension Agent: CustomStringConvertible {
var description: String { // give ourselves a nice, pretty description
if let partner = partner {
return "Agent \(name), who has partner \(partner.name)"
} else {
return "Agent \(name), who has no partner"
}
}
}
然后
var a = Agent(name: "A")
var b = Agent(name: "B")
a.makePartner(with: b)
var c = Agent(name: "C")
var d = Agent(name: "D")
c.makePartner(with: d)
print(a, b, c, d)
代理商A,而合伙人B
经纪人B,有合伙人A
代理商C,合伙人D
代理D,他有合伙人C
然后
a.makePartner(with: c)
print(a, b, c, d)
A代理人(拥有C合伙人)
代理商B,没有合伙人
代理C,拥有合伙人A
代理商D,没有合伙人
和
a.makePartner(with: nil)
print(a, b, c, d)
A代理人,没有合作伙伴
代理商B,没有合伙人
代理商C,没有合伙人
代理商D,没有合伙人