通过实例方法设置时,迅速保留周期问题



如果我创建类似的类代理。对另一个代理对象的参考很薄弱。

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,没有合作伙伴

最新更新