Правильный способ выпуска NSTimer? - PullRequest
4 голосов
/ 19 октября 2010

Как правильно выпустить NSTimer в моем методе dealloc?Он был создан со следующим кодом?

-(void)mainTimerLoop {

     mainTimer = [NSTimer scheduledTimerWithTimeInterval:1/10
                                                  target:self 
                                                selector:@selector(gameLoop) 
                                                userInfo:nil
                                                 repeats:YES];
}

Спасибо

Ответы [ 4 ]

16 голосов
/ 20 октября 2010

Как вы это делаете, вы никогда не нажмете dealloc.Таймер сохраняет свою цель.В этом случае это означает, что таймер сохранил вас.Он не освободит вас, пока не станет недействительным.Так как вы создали таймер, вы также должны сделать его недействительным в некоторый момент до dealloc, потому что сохранение таймера предотвратит появление вашего объекта dealloc ed.

У вас есть два варианта:

  • найти другое место, чтобы сделать недействительным таймер (представление выходит за экран, приложение закрывается, что у вас)
  • установить что-то еще в качестве цели таймера.

В качестве примераиз последнего:

@interface GameLoopTimerTarget : NSObject {
    id owner;  /* not retained! */
}
- (id)initWithOwner:(id)owner;
- (void)timerDidFire:(NSTimer *)t;
@end

@implementation GameLoopTimerTarget
- (id)initWithOwner:(id)owner_ {
    self = [super init];
    if (!self) return nil;

    owner = owner_;
    return self;
}

- (void)timerDidFire:(NSTimer *)t {
#pragma unused (t)
    [owner performSelector:@selector(gameLoop)];
}
@end

/* In your main object… */
/* assume synthesized:
@property (retain, NS_NONATOMIC_IPHONE_ONLY) GameLoopTimer *mainTimerTarget; */
- (void)mainTimerLoop {
    self.mainTimerTarget = [[[GameLoopTimerTarget alloc] initWithOwner:self] autorelease];
    mainTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/10.0 target:self.mainTimerTarget selector:@selector(timerDidFire:) userInfo:nil repeats:YES];
}

- (void)dealloc {
    /* other stuff */
    [timer invalidate], timer = nil;
    [mainTimerTarget release], mainTimerTarget = nil;
    /* more stuff */
    [super dealloc];
}

Обратите внимание, что временной интервал 1.0/10.0 - это также может быть записано 0.1, но это не может быть записано 1/10, как это делениебудет усекать до 0.0.

Также обратите внимание, как это прерывает цикл сохранения:

  • И вы, и ваш таймер сохраняют цель таймера.
  • Вы нажали Delocв обычное время.
  • Затем вы отменяете таймер и освобождаете цель таймера.
  • Затем цель таймера освобождается.
1 голос
/ 19 октября 2010

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

Это может быть нормально для повторяющегося таймера, но опасно для одноразового таймера, поскольку может закончитьсябыть выпущенным до того, как вы получите к нему доступ, чтобы увидеть, является ли он действительным и / или попытаться сделать его недействительным (что приведет к сбою приложения с плохим доступом).Поэтому, если вы планируете каким-либо образом просматривать переменную таймера после ее создания (в том числе проверять ее, делать недействительной и / или освобождать ее), хорошей практикой может быть явное сохранение ее где-то в вашем приложении, а затемОтпустите его и установите его равным nil после того, как он недействителен, и все готово.

Вы можете освободить его и установить его равным nil в одном выражении, если вы объявите его как свойство сохранения.Тогда вы можете написать:

self.timer = nil;
0 голосов
/ 19 октября 2010

у вас есть действительно хороший ответ о NSTimer здесь Как мне использовать NSTimer? там они говорят о том, чтобы остановить повторяющийся NSTimer, выполняющий

[myTimer invalidate];
0 голосов
/ 19 октября 2010

Вам не нужно выпускать его, потому что он будет выпущен автоматически. Все, что создано вспомогательным методом (т. Е. Вы сами не вызываете alloc), является обязанностью вызываемой функции для управления памятью, что обычно означает, что она вызовет autorelease для объекта, который она создает, прежде чем она его вернет.

Я бы назначил таймер для свойства с ключевым словом retain, чтобы убедиться, что он не будет освобожден для вас. Обычно автоматически освобожденные объекты освобождаются в цикле событий, если они не сохраняются.

...