简体   繁体   English

Swift-在基于闭包的配置中避免强大的参考周期

[英]Swift - Avoiding strong reference cycles in closure-based configuration

Please note: I have read many of the (very many) answers and articles on the subject of avoiding strong reference cycles. 请注意:我已经阅读了很多(非常多)的答案和文章,这些主题都是关于避免强参考周期的。 However, I'm looking for guidance on how to handle a specific by-product of avoiding these cycles. 但是,我正在寻找有关如何处理避免这些周期的特定副产品的指南。

In the following example, the class Foo is designed to be configured using a closure. 在以下示例中,将类Foo设计为使用闭包进行配置。 A reference to the closure is cached for later use. 缓存对闭包的引用以供以后使用。

The closure will be called whenever the Model data is needed. 每当需要Model数据时,都会调用该闭包。 In order for Foo to work properly, the data must exist. 为了使Foo正常工作,数据必须存在。

class Foo
{
    typealias ModelGetter = (() -> Model)
    fileprivate var _modelGetter: ModelGetter!

    ...

    func configure(with modelGetter: @escaping ModalGetter)
    {
        _modelGetter = modelGetter
    }

    func printLastestModel()
    {
        // Get the latest model, do something with it.
        precondition(_modelGetter != nil)
        let model = _modelGetter()
        print(model)
    }
}

In the above code, _modelGetter is implicitly unwrapped. 在上面的代码中,_modelGetter被隐式展开。 Although I could define it as an Optional , and unwrap it as needed, Foo always needs the closure to be set in order to work properly, hence the implicit unwrapping. 尽管我可以将其定义为Optional ,并根据需要对其进行解包,但是Foo始终需要设置闭包才能正常工作,因此需要进行隐式解包。

Making an instance of Foo, and configuring it: 制作Foo实例并进行配置:

let foo = Foo()
foo.configure(with: { self.makeModel() })
foo.printLatestModel()

But, this creates a retain cycle. 但是,这创建了一个保留周期。

So, [weak self] is used, and we check for self 's optionality: 因此,使用[weak self] ,我们检查self的可选性:

foo.configure(with: { [weak self] in
    guard let strongSelf = self else { return **WHAT** }
    return strongSelf.makeModel()
})

Problem 问题

This requires that even though self may be nil, the closure still needs to return a Model (ie WHAT?) to the caller of the closure (the Foo instance.) But, since self is nil, I don't have a Model to hand over. 这要求即使self可能为nil,闭包仍然需要向闭包的调用者(Foo实例)返回一个Model(即WHAT?)。但是,由于self为nil,因此我没有Model交出。

Question

Can someone recommend a pattern to use in this situation? 有人可以推荐在这种情况下使用的模式吗? Preferably, I don't want Foo to be checking if the modelGetter is valid or not, or left wondering if the Model is valid. 最好,我不希望Foo检查modelGetter是否有效,或者不知道Model是否有效。 For Foo's purposes, if Foo exists, then it must always be able to get the Model it needs. 出于Foo的目的,如果Foo存在,那么它必须始终能够获得所需的模型。

Or, should I just redesign Foo's needs, to take in to account the possibility of not being able to procure a Model? 或者,我是否应该重新设计Foo的需求,以考虑到无法购买模型的可能性? Thankyou for any help. 感谢您的任何帮助。

If Class is the owner of Foo , it's recommended to set [unowned self] instead of [weak self] . 如果Class是Foo的所有者,建议设置[unowned self]而不是[weak self] It will solve the problem. 它将解决问题。 If one class is the owner of another it will never appear as a problem, but if the logic is wrong it will appear a crash. 如果一个类是另一个类的所有者,它将永远不会出现问题,但如果逻辑错误,它将出现崩溃。 This is not bad because it signals to you that you broke something in the project. 这还不错,因为它向您发出信号,表明您在项目中破坏了某些内容。

But, this creates a retain cycle. 但是,这创建了一个保留周期。

No it doesn't. 不,不是。 foo owns a reference to the closure and the closure owns a reference to self (which is clearly not foo ). foo拥有对闭包的引用,而闭包拥有对self的引用(显然不是foo )。 You will only get a retain cycle, if you have a strong property of type Foo in self and you set it to foo . 如果您self具有Foo类型的强属性并将其设置为foo ,则只会得到一个保留周期。

On the assumption that you are going to do that, I would use one of two patterns: 假设您将要这样做,我将使用以下两种模式之一:

  • I make the assumption as a programmer that self will always be there for the lifetime of foo . 我以程序员的身份假设,在foo整个生命周期中, self永远都会存在。 In that case, I would use [unowned self] instead of [weak self] . 在那种情况下,我将使用[unowned self]而不是[weak self] If my assumption proves to be wrong, the program will abort and I'll be able to fix the bug based on the stack trace. 如果我的假设被证明是错误的,程序将中止,并且我将能够基于堆栈跟踪来修复该错误。 Obviously, you'll want a fairly extensive test suite to validate the assumption as far as possible. 显然,您将需要一个相当广泛的测试套件来尽可能地验证假设。

  • I decide that it is valid for self to disappear in which case you have three choices about how to handle the disappearance: 我认为self消失是有效的,在这种情况下,您对如何处理消失有三种选择:

    • Make the return type of the closure optional ie () -> Model? 使闭包的返回类型为可选,即() -> Model? and make Foo capable of handling a nil model 并使Foo能够处理nil模型
    • Have a default Model that you return if self is nil . 如果selfnil ,则返回一个默认Model
    • Make the closure declare that it throws and throw an error if self is nil . 使闭包声明它抛出并在selfnil抛出错误。

I think I'd probably go with [unowned self] and make sure I explicitly kept a strong reference to it somewhere. 我想我可能会选择[unowned self] ,并确保我在某处明确引用了它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM