有一个具有以下声明的协议:
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])
}
}
我的问题是:
strongSelf
的实施中捕获FirstClass
吗?strongSelf
的实施中捕获SecondsClass
吗?其他问题。假设SecondClass
的{{1}}为suggestions
,这种情况下的模式是什么?
static let
答案 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,定义建议字典的闭包应该在调用后立即执行。