Как правильно уведомить делегата о том, что экземпляр больше не нужен? - PullRequest
0 голосов
/ 13 января 2012

Это мой шаблон:

1) SpecialView создает MessageView и содержит в нем сильную ссылку.

2) Пользователь нажимает кнопку в MessageView, что приводит к его исчезновению.Затем MessageView сообщает своему делегату SpecialView, что он полностью исчез.

3) SpecialView выпускает MessageView.

Проблема заключается в следующем:

- (void)fadedOut:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context {
    [self.delegate messageViewFadedOut:self]; // delegate releases us...
    // self maybe got deallocated... BOOM!
    // now what? method of a zombie returns? stack freaks out?
} // does it even return?

В последней строкеЯ звоню делегату, который, в свою очередь, немедленно освобождает MessageView.-fadedOut: finish: context: вызывается с помощью основного анимационного обратного вызова didStopSelector.

Боюсь, что экземпляр MessageView будет освобожден непосредственно перед тем, как -fadedOut: закончен: контекст: полностью возвращен,вызывая очень неприятные случайные ошибки

Когда-то старый программист-ветеран сказал мне: «Никогда не руби ветку, на которой ты сидишь».

Так, чтобыУбедитесь, что экземпляр сохранился до тех пор, пока этот метод не вернется. Я сделал retain-autorlease-dance перед вызовом делегата:

- (void)fadedOut:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context {
    //[[self retain] autorelease];
    [self.delegate messageViewFadedOut:self]; // delegate releases us...
}

Однако в ARC танцы retain-autorelease больше не разрешены (инструмент миграции выигралне позволяют), и, кажется, нет никакого способа заставить систему ARC сделать что-то подобное.

Поэтому я придумал эту стратегию вместо этого:

- (void)fadedOut:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context {
    [self.delegate performSelector:@selector(messageViewFadedOut:) withObject:self afterDelay:0];
}

Отсроченный executeSelectorнадеюсь, что метод полностью вернется.Насколько я знаю, задержка в 0 все еще гарантирует, что селектор будет выполнен в следующей итерации цикла выполнения, а не сразу.

Есть большая вероятность, что это тоже фальшивка.

Как можноЯ правильно разрешаю эту проблему с одним объектом, прося другой уничтожить последнюю ссылку на него с вероятностью того, что объект get будет освобожден до того, как метод, который сделал вызов другому объекту, получит шанс полностью вернуться?Может ли быть что-то вроде стека трассировки зомби?

И как мне решить что-то подобное под ARC?

1 Ответ

0 голосов
/ 13 января 2012

Честно говоря, я думаю, что вместо того, чтобы пытаться эмулировать retain-autorelease, вы должны убедиться, что к тому времени, когда вызывается метод делегата messageViewFadedOut:, вам все равно, будет ли ссылка на ваше представление сообщениявышел.Контракт для метода willFadeOut: может предполагать, что он не будет освобожден, но метод fadedOut: или didFadeOut: должен соответствовать объекту, который был освобожден.

Идеальным решением было бы для вашего dealloc метода специально избежать неприятных случайных ошибок, которых вы боитесь, отменив любую активную анимацию затухания, которая происходит (где-то храните ссылку на нее).Таким образом, вам все равно, как и когда он доберется до dealloc, потому что dealloc знает, как сделать X, чтобы предотвратить оставление любого состояния объекта или визуальных аномалий после его смерти.

Так что просто используйте ваше решение(performSelector:withObject:afterDelay:) или, возможно, блок GCD:

- (void)fadedOut:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context
{
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 250 * NSEC_PER_MSEC), // 250ms
                   dispatch_get_current_queue(),
                   ^{
                        [self.delegate messageViewFadedOut:self];
                   });
}

Кроме того, ARC может просто autorelease немедленно, почему бы вам не протестировать этот фрагмент кода несколько раз и посмотреть, что произойдет?Поместите точку останова в dealloc и посмотрите, вызывается ли она до возврата метода.

...