Могу ли я использовать didSet в deinit?
Я добавил переменную Timer в свой класс и использовал ее наблюдатель didSet для аннулирования старого значения
var timer: Timer? {
didSet { oldValue?.invalidate() }
}
deinit {
timer = nil
}
Я думал, что этого будет достаточно, чтобы сделать недействительным таймер, когда класс деинициализирован, но похоже, что didSet не вызывается. Это почему? Не работают ли наблюдатели во время деинициализации?
2 ответа
Давайте положим ответ здесь, чтобы мы могли закрыть это.
Похоже, что наблюдатели за имуществом не бегают во время
deinit
, Это кажется параллельным с тем фактом, что наблюдатели за недвижимостью не работают во времяinit
Но, в отличие от последнего, первое, кажется, нигде четко не задокументировано.Вы можете обойти это путем семантического обмана, но не делайте этого! Это похоже на ошибку (и я ее подал).
Исходный вариант использования был не очень хорошим для начала. Скрытие аннулирования таймера в замене звучит как потенциальный кошмар обслуживания. Согласен, что аннулирование и замена идут вместе, как ветчина и яйцо, и я всегда пишу метод, который делает недействительным и заменяет, в этом порядке, и направляет все через этот метод. (Это может быть применено в случае необходимости, но я не буду вдаваться в подробности.) Этот метод может быть вызван во время
deinit
,
ДОПОЛНИТЕЛЬНОЕ ПРИМЕЧАНИЕ: при использовании таймера будьте осторожны с проблемами управления памятью! Вы можете легко попасть в ситуацию, когда deinit
никогда не вызывается, потому что вы сохраняете таймер, но таймер удерживает вас. Затем вам не удастся сделать недействительным таймер, и весь ваш контроллер представления утечет. Вы не жалуетесь на это в своем вопросе, но это связанный вопрос, поэтому я подумал, что мне лучше пометить это.
позвоните так, если вы хотите, чтобы сеттеры запускали
deinit {
{ timer = nil }()
}