Сбой iPhone - сообщение отправлено освобожденному экземпляру - PullRequest
2 голосов
/ 22 февраля 2012

Хорошо, вот ошибка, которую я получаю:

    -[CFRunLoopTimer invalidate]: message sent to deallocated instance 0x109b05a0 (gdb)

Вот код, вызывающий сбой:

    if (waitingOpponentTimer) {
      [waitingOpponentTimer invalidate]; //<-- Crash/error occurs here
      waitingOpponentTimer = nil;
    }

И в других местах:

    NSTimer* waitingOpponentTimer;

А также:

    waitingOpponentTimer = [NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(waitingOpponentTimeOut)userInfo:nil repeats:NO];

Никакого другого случая ожиданияOpponentTimer НЕТ, кроме тех, которые я показал выше. Действие waitOpponentTimeOut просто устанавливает несколько переменных и ничего не делает с таймерами или waitOpponentTimer.

Я попробовал все следующие операторы IF, чтобы предотвратить достижение недействительного оператора:

    if (waitingOpponentTimer) {
    if ([waitingOpponentTimer retainCount] > 0) {
    if (waitingOpponentTimer.isValid) {
    if (waitingOpponentTimer != nil) {

Но во всех случаях он все еще проходит через оператор IF, а затем вызывает сбой с оператором invalidate.

Итак, мой вопрос: почему / как недействительно, вызывая ошибку, когда объект имеет значение Valid и не равен nil, а его retainCount больше нуля?

Есть ли другой способ проверить это, чтобы предотвратить недействительность?

Я полный новичок в программировании на iphone и потратил несколько часов, пытаясь понять, что это, но не могу понять, что я делаю неправильно. Любая помощь и предложения приветствуются!

EDIT: Просто чтобы уточнить, я использую это, чтобы вручную остановить таймер, прежде чем он запустится. Я понимаю, что если он заканчивается, он делает себя недействительным, поэтому я использую оператор IF, чтобы проверить, был ли он уже признан недействительным (но он не работает). Поэтому я думаю, что таймер уже сделал себя недействительным, когда произошел этот сбой, но как я могу проверить, если он уже признан недействительным?

EDIT: Хорошо, я отметил правильный ответ ниже. Я не знаю, есть ли на самом деле причина, по которой код получает операторы IF, когда таймер не был сохранен и уже аннулировал себя, но ответ заключается в том, чтобы всегда использовать RETAIN, если вы собираетесь использовать таймер в операторе IF. .

Вот соответствующая информация: Есть ли какая-либо причина для сохранения запланированного NSTimer, если вам не нужно его аннулировать?

Ответы [ 3 ]

6 голосов
/ 22 февраля 2012

Вы используете ARC?

waitingOpponentTimer = [[NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(waitingOpponentTimeOut)userInfo:nil repeats:NO] retain];
1 голос
/ 22 февраля 2012

попробуйте вызвать isValid перед запуском таймера

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

подумай об этом

 waitingOpponentTimer = [NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(waitingOpponentTimeOut)userInfo:nil repeats:NO];

 waitingOpponentTimer = [NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(waitingOpponentTimeOut)userInfo:nil repeats:NO];

    [waitingOpponentTimer invalidate]

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

if ([waitingOpponentTimer isValid]
{
    [waitingOpponentTimer invalidate]

     waitingOpponentTimer = [[NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(waitingOpponentTimeOut)userInfo:nil repeats:NO] retain];
}else{

     waitingOpponentTimer = [[NSTimer scheduledTimerWithTimeInterval:10.0f target:self selector:@selector(waitingOpponentTimeOut)userInfo:nil repeats:NO] retain];
}
0 голосов
/ 22 февраля 2012

Скорее всего, вам не нужно аннулировать таймер.Поскольку таймер не повторяется, он аннулирует себя, как только назначенное время достигнет конца.Это может быть причиной того, что приложение также падает.Если таймер достиг конца своего запуска, он отправляет себе сообщение о недействительности, поэтому, когда вы вызываете его позже, он не знает, что делать, так как он уже был признан недействительным.Поэтому я предлагаю просто игнорировать аннулирование, так как оно будет обрабатывать себя (если оно не повторяется)

...