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