NSTimer отключает деаллок в UIView

@interface someview:UIView{
  NSTimer* timer;
}
@end

@implementation someview

-(void)dealloc{
  NSLog(@"dealloc someview");
  [timer invalidate];
  timer = nil;
}
-(void)runTimer{
//
}
-(void)someMethod{

  timer = [NSTimer timerWithTimeInterval:2.0f target:self selector:@selector(runTimer) userInfo:nil repeats:YES];
}

@end

Освобождение someview НЕ приведет к вызову Dealloc, и таймер продолжит работать.

Если я закомментирую часть "timer = [NSTimer schedule....", будет вызван Dealloc. Это означает, что вся остальная часть моего кода работает правильно, а виноват таймер. Метод runTimer пуст, а это значит, что это просто таймер.


person ssj    schedule 14.04.2011    source источник


Ответы (3)


NSTimer сохраняет цель. Следовательно, таймер должен быть аннулирован до того, как ваше представление будет освобождено.

person MarkPowell    schedule 14.04.2011
comment
В Dealloc superview я поместил [someview killtimer] и [someview release], таймер стал недействительным, но Dealloc по-прежнему не вызывается - person ssj; 15.04.2011
comment
Тогда что-то еще сохраняет вид. - person bbum; 15.04.2011
comment
Не знаю, почему метод killtimer, который я реализовал, не сработал в первый раз, когда я попробовал его... но теперь он работает. - person ssj; 15.04.2011

Я думаю, что лучшим решением при использовании NSTimer внутри UIView является переопределение метода removeFromSuperview;

- (void)removeFromSuperview
{
    [timer invalidate];
    timer = nil;

    [super removeFromSuperview];
}

Единственное, что нужно иметь в виду, это то, что вам нужно убедиться, что timer не является нулевым объектом, потому что removeFromSuperview также может автоматически вызываться из других методов super Dealloc UIView. Вы можете обернуть условие для проверки.

person jfeldman    schedule 19.05.2011
comment
removeFromSuperview отправит в представление сообщение об освобождении. поэтому я думаю, что мы можем сделать это в самом делелоке. - person SNR; 10.02.2012

Как упоминалось выше, таймеры сохраняют свои цели. Пока таймер не станет недействительным, между таймером и представлением существует цикл сохранения, поэтому представление не будет освобождено.

Я бы аннулировал таймер, когда он удаляется из иерархии представлений путем создания подкласса didMoveToSuperview, это вызывается системой, когда происходит изменение, связанное с представлением (например, изменения суперпредставления). 'removeFromSuperview' вызывается только тогда, когда removeFromSuperview вызывается в UIView

- (void)didMoveToSuperview
{
    [super didMoveToSuperview];

    if (!self.superview)
    {
        [timer invalidate];
        timer = nil;
    }
}
person Ash    schedule 18.12.2013
comment
Проблема не обязательно вызвана циклом сохранения. Даже если у вас есть слабая ссылка (или нет) на таймер, таймер будет сохранен циклом выполнения, в котором он запланирован. - person Anthony Mattox; 12.02.2015