Swift 3:在@escaping闭包中捕获强大的自我,而不需要异步工作

时间:2016-11-28 12:13:29

标签: swift asynchronous grand-central-dispatch dispatch-async

有一个具有以下声明的协议:

typealias SuggestionSourceCallback = ([Suggestion]) -> ()

protocol SuggestionSource {
    func suggest(_ query: SuggestionQuery, callback: @escaping SuggestionSourceCallback)
}

两个类实现此协议。第一类异步获取建议(通过GCD

final class FisrtClass: SuggestionSource {
    private let queue = DispatchQueue(label: "my.app.queue", attributes: [])
    private var lastQuery: SuggestionQuery?
    // ...
    func suggest(_ query: SuggestionQuery, callback: @escaping SuggestionSourceCallback) { 
        self.queue.async { [weak self] in

            // capturing strong self
            guard let strongSelf = self else {
                return
            }

            // referencing self here, for example
            guard self.lastQuery == query else {
                return
            }

            // suggestions is a local variable
            var suggestions: [Suggestion] = []

            // ... 

            DispatchQueue.main.async {
                callback(suggestions)
            }
        }
    }
}

......而第二课同步进行

final class SecondClass: SuggestionSource {
    // ...
    func suggest(_ query: SuggestionQuery, callback: @escaping SuggestionSourceCallback) {
        // ...
        callback(self.suggestions[query])
    }
}

我的问题是:

  1. 我应该在strongSelf的实施中捕获FirstClass吗?
  2. 我应该在strongSelf的实施中捕获SecondsClass吗?
  3. 更新

    其他问题。假设SecondClass的{​​{1}}为suggestions,这种情况下的模式是什么?

    static let

2 个答案:

答案 0 :(得分:1)

SecondClass中,无需创建strongSelf变量。你会把它放在哪里?关键是self无论如何都保证不是nil,因为你在其中一种方法的范围内运行。

您的其他问题也是如此,但原因不同。 suggestions现在为static,因此前缀为self是语法问题(我假设您的意思也是suggest方法前缀为static

但是,在FirstClass中,捕获strongSelf与捕获它之间存在细微差别。

由于您使用的是[weak self],因此当您输入该区块时,self可能为nil,因此无论如何您都需要对此进行检查。一种方法是重复使用可选链接,即:

self?.doSomething()
self?.doSomethingElse()

这就是说:

  

如果我有自己的引用,做某事。如果我仍然有一个   引用自己,做其他事情

添加strongSelf变量:

guard let strongSelf = self else {
  return
}
strongSelf.doSomething()
strongSelf.doSomethingElse()

...你说的是:

  如果您引用self

执行某些操作执行其他操作,   否则什么都不做。

所以,你保证如果第一件事情发生,那么第二件事情也是如此。您采取的方法取决于您的申请。

答案 1 :(得分:-2)

场景1是[unowned self]的合适人选。

在这种情况下,如果队列存在,那么self也是如此,因此在不保留的情况下引用self是安全的。

注意:当您可以确定块的生命周期与捕获的变量直接相关时,您应该使用unowned。在其他情况下,无主可能导致间歇性崩溃(这很难调试)。

同样无主,性能比弱,因此在使用source安全的地方应该是首选。

对于方案2,我可以确定的任何块都不会捕获self,因此您根本不需要担心它。

对于更新,您仍然不捕获self,定义建议字典的闭包应该在调用后立即执行。