如果我创建类似的类代理。对另一个代理对象的参考很薄弱。
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,则只有邦德的deinit被打电话而不是sam。
,但是如果我使用
sam?.partner = bond //THIS WORKS
bond?.partner = sam //THIS WORKS
而不是调用makepartner,而是两个deinit被调用。您能解释一下为什么会发生这种情况吗?通过MakePartner方法设置合作伙伴时,哪个引用剩余到SAM。
这是一个相关的问题。在上面的应用程序中,效果很好。如果您仍然想在操场上解决此问题,您可以通过替换来解决此行为:
bond?.makePartner(sam) - this line
使用这些行:
bond?.partner = sam
sam?.partner = bond
这里没有"强参考周期"(以前已知"保留周期")。您的weak
参考可以阻止这一点。
未能看到两个被划分的对象的证据不是您问题中代码的结果。只是一些特殊的操场行为。
如果您在应用程序中运行此操作,则可以正常运行。
,有趣的是,当我在xcode 10.2 beta 2操场上测试它时,它的表现也正确。
搁置此问题,makePartner
有一些问题。我敢打赌,您不在乎,这仅仅是对弱关系的考验,但是如果您确实在乎,我想澄清这些问题:
-
如果" A"是" B"的合作伙伴,但是我们现在想与" C"合作。您的代码将使彼此成为" A"one_answers" 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,有合伙人
特工D,没有合作伙伴
和
a.makePartner(with: nil)
print(a, b, c, d)
代理A,没有合作伙伴
特工B,没有合伙人
没有合伙人的特工C
特工D,没有合作伙伴