Ответ 1
Важно отметить, что GCD dispatch_async НЕ приведет к циклу сохранения. Другими словами, когда блок завершил выполнение, GCD не сохранит никаких ссылок, сделанных внутри блока.
То же самое не относится к сильным ссылкам между классами или сильным ссылкам в закрытии, назначенным для свойства экземпляра. Документация для Apple
В этом примере правильным ответом является вариант 2, чтобы определять захваты только при первом закрытии.
В целях тестирования я немного изменил код:
class ExampleDataSource {
init() {
print("init()")
}
deinit {
print("deinit")
}
var content: Any?
func loadContent() {
print("loadContent()")
ContentLoader.loadContentFromSource() { [weak self] loadedContent in
dispatch_async(dispatch_get_main_queue()) {
print("loadedContent")
self?.content = loadedContent
}
}
}
}
class ContentLoader {
class func loadContentFromSource(completion: (loadedContent: Any?) -> Void) {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_UTILITY, 0)) {
sleep(5) // thread will hang for 5 seconds
completion(loadedContent: "some data")
}
}
}
Сначала создаю, var myDataSource: ExampleDataSource? = ExampleDataSource()
.
Затем я запустил myDataSource.loadContent()
.
Прежде чем обработчик завершения получит шанс запустить, я установил myDataSource = nil
, удалив все ссылки на него.
Консоль отладки указывает, что ссылка на self не была сохранена:
init()
loadContent()
deinit
loadedContent
Похоже, мы нашли наш ответ! Но только ради завершения, дайте возможность проверить альтернативы...
Если [weak self]
вместо этого записывается только на внутреннем большинстве закрывающих закрытий, GCD сохранит ExampleDataSource
, пока блок не завершит выполнение, что объясняет, почему отладка будет выглядеть следующим образом:
init()
loadContent()
loadedContent
deinit
То же самое произойдет, если список захвата не включен, и мы никогда не по желанию не разворачиваем self
, хотя компилятор пытается предупредить вас!
Хотя технически некорректно включать [weak self]
во все трейлинг-блокировки, это отвлекает от читаемости кода и не чувствует себя "Swift-like".