Вопрос по iphone – NSTimer не останавливается

22

У меня есть таймер, который срабатывает, когдаviewWillAppear метод вызывается и делает недействительным, когдаviewDidDisappear метод вызывается. Но после определенного количества переключений между представлениями таймер продолжает срабатывать даже после того, как он был отменен. В чем проблема?

Вот мой код:

NSTimer *timer;

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    timer = [NSTimer scheduledTimerWithTimeInterval: 0.2f
                     target: self
                     selector:@selector( timerAction )
                     userInfo:nil
                     repeats:YES];
}

-(void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    [timer invalidate];
    timer = nil;
}

-(void) timerAction
{
    NSLog(@"timerAction");
}

Ваш Ответ

12   ответов
0

viewWillDisappear:

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];
    [timer invalidate];
    [timer release];
    timer = nil;
}

This shouldn't cause the timer to keep firing though...

У Бена Готоу есть правильный ответ здесь. Вы должны сохранить таймер после его создания, а затем сделать его недействительным и отпустить его, если хотите, чтобы он перестал перезванивать вам.
В этом случае приложение падает, потому что таймер уже выпущен. Ilya Suzdalnitski
Вы не можете его сохранить, так как цикл выполнения сделает это, но это хорошая идея, если вы хотите быть в безопасности.
0

invalidate DOCO говорит

& quot; Цикл выполнения удаляет и освобождает таймер либо непосредственно перед возвратом метода invalidate, либо в какой-то более поздний момент. & quot;

Я полагаю, что ваш удаляется в какой-то более поздний момент.

2

но вам нужно сохранить ссылку на таймер, который возвращается от scheduleTimerWithInterval :. Без этого ваш указатель на таймер может оказаться недействительным к тому времени, когда вы остановите его.

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    timer = [[NSTimer scheduledTimerWithTimeInterval:0.2f target:self selector:@selector(timerAction) userInfo:nil repeats:YES] retain];
}

- (void)viewDidDisappear:(BOOL)animated
{
    [timer invalidate];
    [timer release];
    timer = nil;
    [super viewDidDisappear:animated];
}

- (void)dealloc
{
    [timer invalidate];
    [timer release];
    timer = nil;
    [super dealloc];
}

Кроме того, попробуйте установить точку останова в viewDidDisappear и убедитесь, что она вызывается!

0

NSRunLoopCommonModes:

[[NSRunLoop currentRunLoop] addTimer:myTimer forMode:NSRunLoopCommonModes];

затемinvalidate метод будет работать.

6

Метод, вызываемый таймером, должен иметь определение

- (void)methodName:(NSTimer *)aTimer;

Таким образом, метод имеет экземпляр таймера, который был запущен. То, как вы это делаете, метод не будет знать, был ли таймер недействительным или нет.

Попробуйте изменить инициализацию таймера на

timer = [NSTimer scheduledTimerWithTimeInterval: 0.2f target: self selector:@selector(timerAction:) userInfo:nil repeats:YES]

и метод для

-(void) timerAction:(NSTimer *)aTimer{...}

надеюсь, это поможет

Сделайте недействительным объект таймера в методе и сделайте его нулевым. Также убедитесь, что NSTimer объявлен как сохраняемое свойство. Это работает для меня.
Это не будет иметь никакого эффекта.
@rpetrich Если вы можете дать еще меньше информации в своем ответе, это было бы здорово, чувак!
1
**In .h class**

@interface 
{
NSTimer * theTimer;

}


**in .m class**

//put this code where you want to calling the NSTimer function

        theTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(updateCounter:) userInfo:nil repeats:YES];



- (void)updateCounter:(NSTimer *)theTimer 
{

   // write your code here for counter update 

}


// put this code to Stop timer:

    [theTimer invalidate];
    theTimer = nil;
0

Это работает для меня

dispatch_async(dispatch_get_main_queue(), ^{
    [timer invalidate];
});
1

Это помогло мне в Swift

override func viewWillDisappear(animated: Bool) {
    super.viewWillDisappear(animated)

    dispatch_async(dispatch_get_main_queue(),{ [weak self] in

        self?.idleTimer?.invalidate()
        self?.idleTimer = nil

    })

}
38

Я должен был сохранить ссылку на таймер, сохранив его. :) Я задавал этот вопрос 5 месяцев назад, и это удивительно, как много опыта я приобрел. :)

timer = [ [NSTimer scheduledTimerWithTimeInterval: ...] retain];
...
...
[timer invalidate];
[timer release];
Как это сделать в ARC, когдаretain а такжеrelease не допускаются?
Для iOS 7/8, см. Ответ ниже об использовании парыrepeats: NO таймеры.
0

Я не могу освободить свой экземпляр, если таймер все еще работает, поэтому я должен остановить его перед вызовом:

- (void)stopTimer
{
    [timer invalidate];
    [timer release];
    timer = nil;
}

После вызова этого метода мой таймер действительно останавливается

0

- (void)viewWillAppear:(BOOL)animated снова вызывается.

Фактически он вызывается каждый раз, когда вы переключаете представления или после того, как вы отклоняете модальное представление. По сути, каждый раз, когда ваш вид фактически появляется на экране, а не только в первый раз.

Таким образом, в этом случае таймер перезапускается, хотя ранее он был недействительным.

14

ня, поэтому я сделал это,

где вы хотите запустить таймер,

[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:NO];

Метод, который вызывает таймер,

-(void)timerMethod
{
    // do what you need to do

    if (needs to be called again) {

        [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:NO];        
    }
}

надеюсь это поможет,

Действительно ... Для меня это похоже на ошибку Apple. Метод invalidate не работает из-за повторного значения BOOL, установленного в YES, кажется мне немного странным
Это единственное, что работает и для меня ...
Эта ошибка все еще существует в iOS8. Это единственный способ решить проблему.

Похожие вопросы