Проблема, делающая недействительным NSTimer в dealloc

Что-то как

void debugAssert(bool val, const char* file, int lineNumber);
#define assert(x) debugAssert(x,__FILE__,__LINE__);

Так, чтобы Вы могли просто, например, иметь

assert(n == true);

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

, Если Вы используете нормальный вызов функции такой в качестве

void assert(bool val);

вместо макроса, все, которое можно добраться, Ваш утверждать номер строки функции, распечатанный к журналу, который был бы менее полезным.

5
задан Prashant 9 December 2009 в 19:39
поделиться

2 ответа

I did some research and tests, and could figure out the answer to my own question. Ok, here it goes:

Whenever we assign self as target to the NSTimer, the timer holds a reference to our object. If the timer is repeating (or has a long time period), it would not get invalidated on its own (or will take too long to invalidate automatically, if not repeating). So, even if the object is released in the meantime, it wouldn't call the dealloc method, as the retain count would at least be 1. Now, I was forcibly trying to dellocate my object by calling repeated releases on it till the retain count became 0. That was my mistake.

But if you do not do that, your object will keep alive, and you will eventually have a memory leak as you lose the rest of the references to that object by various releases. The only one kept will be with the NSTimer. This sounds like a deadlock situation. My code crashed, because when the delloc tried to invalidate the NSTimer, it tried to release the reference that it was holding. But since I had been a smartass and reduced the retain count to 0 already, that would cause a memory exception.

To solve this, firstly I cleaned up my act and removed the code to forcibly dellocate the object. Then just before I wanted the object to be dellocated, I called the NSTimer's invalidate function. This released the target instance that the Timer had. After that, calling release on my object successfully dellocated it.

The bottom line is, if your object has NSTimers that repeat or do not invalidate (get over) automatically, never invalidate them in the delloc function. The delloc will not get called till the timer is holding the instance to your object. Instead have a cleanup function to invalidate the timers, before releasing the object. That is the solution that I came up with. If there is a better one out there, I most certainly want to know.

16
ответ дан 18 December 2019 в 06:50
поделиться

Есть несколько вещей, которые вы должны решить, чтобы очистить это.

Объявление вашего класса немного не так. Если вы хотите наследовать от NSObject, правильный синтаксис:

@interface GObject : NSObject

В вашей реализации вы должны реализовать - (id) init , а не - (void) Initialize . Нет метода экземпляра - (void) Initialize ... есть статический метод + (void) initialize . Обратите внимание на + и существенную разницу в капитализации): метод initialize вызывается в вашей программе один раз перед тем, как класс получит свой первый метод.

В этом случае ваш метод Initialize не вызывается вообще (он написан неправильно , и это метод экземпляра, а не статический метод). Вместо этого вы хотите реализовать init , который является назначенным инициализатором для экземпляров NSObject:

- (id)init {
    if (self = [super init]) {
        self.m_Timer = [NSTimer scheduledTimerWithTimeInterval:5.0 
                   target:self 
                   selector: @selector(TimerCallback:) 
                   userInfo: nil 
                   repeats: YES];
    }
    return self;
}

Наконец, обязательно используйте символ @ перед оператором свойства:

@property(nonatomic, retain) NSTimer* m_Timer;

И не забудьте синтезировать его в своей реализации:

@implementation GObject

@synthesize m_Timer;
5
ответ дан 18 December 2019 в 06:50
поделиться