Как Unowned ссылка работает с переменными захвата в Swift
Есть много обучающих программ по ARC. Но я не понимаю четкую работу неизвестных или слабых как то, как переменные, захваченные ссылкой, становятся нулевыми.
Apple Document:
Определите перехват в замыкании как неподтвержденную ссылку, когда замыкание и захваченный экземпляр всегда будут ссылаться друг на друга и всегда будут освобождены одновременно.
class RetainCycle {
var closure: (() -> Void)!
var string = "Hello"
init() {
closure = { [unowned self] in
self.string = "Hello, World!"
}
}
}
замыкание ссылается на self внутри своего тела (как способ ссылки на self.string), замыкание захватывает self, что означает, что оно содержит сильную ссылку на экземпляр RetainCycle. Сильный референтный цикл создается между ними. По несостоявшемуся разрушающему циклу.
Но я хочу понять, какой сценарий не будет взаимно освобожден одновременно, и Unowned self становится нулевым, просто хочет его сломать.
2 ответа
Когда я получаю, вы спрашиваете, как "я" может быть нулевым, пока работает closue. Если я правильно понял, я могу привести вам довольно похожий пример, который я видел раньше.
Я написал расширение для UIImageView, которое загружает изображение по заданной ссылке и устанавливает себя так.
public extension UIImageView{
func downloadImage(link: String){
let url = URL(string:link)
URLSession.shared.dataTask(with: url){ [unowned self]
if let image = UIImage(data: data){
DispatchQueue.main.async{
self.image = image
}
}
}
task.start()
}
}
Но была проблема. Загрузка изображения является фоновой задачей. Я установил метод завершения на UrlSession и увеличил его счетчик ссылок. Таким образом, мое закрытие остается, даже если imageView отключен.
Так что же произойдет, если я закрою viewController
это держит мой UIImageView
, прежде чем загрузка завершена. Он падает из-за imageView
освобожден, но закрытие все еще остается и пытается достичь его image
имущество. Как я понимаю, вы хотите научиться этому.
Я изменился unowned
ссылка на weak
Для решения этой проблемы.
это означает, что он содержит сильную ссылку на экземпляр RetainCycle
Это не правда У него есть неизвестная ссылка на экземпляр RetainCycle. Это не то же самое, что сильная ссылка.
Но я хочу понять, какой сценарий не будет взаимно освобожден одновременно, и Unowned self становится равным нулю, я просто хочу его сломать.
В любой момент closure
захвачен чем-то вне RetainCycle
и так переживает своего владельца
var rc: RetainCycle? = RetainCycle() // create an RC
let cl = rc?.closure // Hold onto its closure
rc = nil // Deallocate the RC
cl?() // Access the closure safely, but its reference to `self` is invalid. Crash.
Как правило, замыкания, которые включают unowned self
должно быть невозможно ссылаться за пределами self
, Иногда трудно понять, что это правда. Например, вот случай, когда недавно произошел сбой приложения, над которым я работаю:
var completion: (() -> Void)?
...
DispatchQueue.main.async { [unowned self] in
self.completion()
self.completion = nil
}
Это нормально, но если self
освобождается между временем, когда он ставит в очередь блок главной очереди, и временем, когда блок запускается, boom.
Кстати, в этом случае правильный ответ будет регулярным, сильным self
, Мы хотим, чтобы цикл сохранения сохранял этот объект до тех пор, пока не запустится его обработчик завершения, после чего блок исчезнет, ссылка на self
уходит и self
правильно освобожден. Так [weak self]
тоже не всегда ответ.