Подкласс UIView не освобождается

У меня есть подкласс UIView, который не освобождается. Я знаю, что только один класс создает экземпляр моего представления. На мой взгляд, у меня есть NSTimer ivar. Если я закомментирую этот таймер и когда я нажму кнопку отмены, которая находится на этом контроллере представления, вызывается расселение в этом представлении. Если я не закомментирую таймер, Dealloc никогда не вызывается.

//CustomUIView
- (id) initWithFrame:(CGRect)frame 
{
    self = [super initWithFrame:frame];
    if (self) {
        _pollTimer = [[NSTimer scheduleTimerWithTimeInterval:0.2 target:self selector:@selector(onPollTimerFired:) userInfo:nil repeats:YES] retain];
    }
}

Я хочу сохранить ссылку на этот таймер, потому что бывают случаи, когда я хочу приостановить таймер. Теперь у меня может быть свойство в моем представлении для таймера, а в методе Dealloc класса, который имеет ссылку на мой пользовательский интерфейс, я могу аннулировать его перед выпуском указанного представления. Мне не очень нравится такой подход, потому что я не хочу показывать этот таймер внешним объектам.

У кого-нибудь есть идеи?


person Community    schedule 24.06.2012    source источник
comment
NSTimer сохраняет свою цель...   -  person fbernardo    schedule 24.06.2012


Ответы (3)


NSTimer всегда сохраняет свою цель. Это имеет два последствия:

  1. Вы не должны иметь представление (которое является целью таймера) сохранять таймер, так как это создаст цикл.

  2. Ваше представление никогда не будет освобождено, пока таймер остается активным.

Вместо этого вы должны вызывать invalidate на таймере всякий раз, когда ваше представление завершает работу с ним. Как только это будет сделано, представление будет deallocated, когда его счетчик ссылок станет равным нулю.

Обычно это происходит, когда представление удаляется из его суперпредставления; если вы хотите, чтобы он продолжал использовать свой таймер до тех пор, пока это не произойдет, а затем был освобожден, вы можете переопределить removeFromSuperview, чтобы сделать таймер недействительным, а затем вызвать super.

person rickster    schedule 24.06.2012
comment
Как этот ответ может иметь только один голос? (Ну, теперь два...) Переопределение removeFromSuperview было для меня ключом, спасибо, Рикстер. - person BP.; 19.03.2013

Редактировать:

В вашем методе -dealloc попробуйте следующее:

- (void) dealloc
{
    [_pollTimer invalidate];

    /*
        If not using ARC:
        [_pollTimer release], _pollTimer = nil;
        [super dealloc];
    */
}

Вы забыли вызвать super реализацию -initWithFrame:! Упс!

- (id) initWithFrame:(CGRect)frame 
{
    if ((self = [super initWithFrame:frame]))
    {
        _pollTimer = [[NSTimer scheduleTimerWithTimeInterval:0.2 target:self selector:@selector(onPollTimerFired:) userInfo:nil repeats:YES] retain];
    }
    
    return self;
}

Это должно работать намного лучше.

person Alexsander Akers    schedule 24.06.2012
comment
собственно, я так и делаю. извините, забыл, но это в моем фрагменте кода. - person ; 24.06.2012
comment
Если NSTimer сохраняет свою цель, счетчик сохранения не достигнет нуля, и поэтому объект не будет dealloced. Когда вы закончите с этим представлением, вам нужно взять этот код из Dealloc и вызвать его в другом месте. - person Rob; 24.06.2012

Вы не должны сохранять таймер. Запланируйте таймер следующим образом: _pollTimer = [NSTimer scheduleTimerWithTimeInterval:0.2 target:self selector:@selector(onPollTimerFired:) userInfo:nil repeats:YES]; и всякий раз, когда вы хотите сделать его недействительным: [_pollTimer invalidate]

person Zeus Alexander    schedule 24.06.2012