Как Unowned ссылка работает с переменными захвата в Swift - PullRequest
1 голос
/ 05 марта 2019

На ARC много учебников.Но я не понимаю четкую работу неизвестных или слабых, как то, что ссылочные захваченные переменные становятся нулевыми.

Apple Document:

Определение захвата в замыкании как неподдерживаемой ссылки, когдазамыкание и захваченный экземпляр всегда будут ссылаться друг на друга и всегда будут освобождены в одно и то же время.

class RetainCycle {
        var closure: (() -> Void)!
        var string = "Hello"

        init() {
            closure = { [unowned self] in
                self.string = "Hello, World!"
            }
        }
    }

замыкание ссылается на себя внутри своего тела (как способ ссылкиself.string), замыкание захватывает self, что означает, что оно содержит сильную ссылку на экземпляр RetainCycle.Сильный референтный цикл создается между ними.По неизвестному его разрывному ссылочному циклу.

Но я хочу понять, какой сценарий не будет взаимно освобожден в одно и то же время, и Unowned self становится нулевым, просто хочу его аварийно завершить .?

Ответы [ 2 ]

1 голос
/ 05 марта 2019

Когда я получаю, вы спрашиваете, как self может быть нулевым во время работы 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, чтобы решить эту проблему.

0 голосов
/ 05 марта 2019

, что означает, что он содержит сильную ссылку на экземпляр 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 освобождается между временем, когда он ставит в очередь блок главной очереди, и временем, когдаблок бежит, бум.

Кстати, в этом случае правильный ответ будет обычным, сильным self.Мы хотим, чтобы цикл сохранения удерживал этот объект до тех пор, пока не будет запущен обработчик его завершения, после чего блок исчезнет, ​​ссылка на self исчезнет, ​​и self будет должным образом освобожден.Так что [weak self] тоже не всегда ответ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...