Путаница в том, куда следует поместить [непризнанное "я"

У меня есть сохраненный цикл, поэтому deinit моего viewcontroller не будет вызываться, и я пытаюсь решить эту проблему с моим добавлением [unowned self], но я не слишком уверен, куда поместить unowned в моих случаях:

Случай 1

class YADetailiViewController: UIViewController {
 var subscription: Subscription<YAEvent>?

 override func viewDidLoad() {
    super.viewDidLoad()
    if let query = self.event.subscribeQuery() {
        self.subscription = Client.shared.subscribe(query)
        self.subscription?.handle(Event.updated) {
            query, object in
            DispatchQueue.main.async {
                [unowned self] in// Put unowned here won't break the cycle, but it does compile and run 
                self.pageViewLabel.text = String(object.pageViews) + " VIEW" + ((object.pageViews > 1) ? "S" : "")
            }
        }
    }
 }
}

Дело 2

 override func viewDidLoad() {
    super.viewDidLoad()
    if let query = self.event.subscribeQuery() {
        self.subscription = Client.shared.subscribe(query)
        self.subscription?.handle(Event.updated) {
            [unowned self] query, object in // Put unowned breaks the cycle, and deinit is called
                DispatchQueue.main.async { 
                    self.pageViewLabel.text = String(object.pageViews) + " VIEW" + ((object.pageViews > 1) ? "S" : "")
                }
            }
        }
    }

Мне любопытно, в чем различия между этими двумя сценариями и почему один работает, но не другой

1 ответ

Действительно, как правильно заметил @matt, проблема связана со временем, когда self захвачен На самом деле в этом коде self захватывается дважды:

  • Когда внешнее закрытие передается handle метод
  • Когда внутреннее закрытие передается async метод (во время handle закрытие исполнения)

Внешнее закрытие необходимо self передать его внутреннему закрытию, иначе внутреннее закрытие не сможет захватить его.

Характер или удерживающий цикл следующий: self(YADetailiViewController) -> subscription -> закрытие (handle параметр) -> self, Чтобы разорвать этот цикл, достаточно не сохранить self в этом (внешнем) закрытии. Вот почему второй пример кода работает.

Второй захват self (во внутреннем закрытии) происходит только тогда, когда внешнее закрытие выполняется и продолжается до тех пор async блок выполняется - обычно это довольно короткое время.

В первом примере кода вы не нарушаете цикл. Второй захват self не бывает, но первый (вызывающий твой цикл) все еще присутствует.

И если ваш handle Закрытие все еще может быть вызвано, когда контроллер представления уже деактивирован / освобожден, тогда, как предложено @AdrianBobrowski, вы должны использовать weak вместо unowned чтобы предотвратить возможный сбой.

Другие вопросы по тегам