views:

59

answers:

3

I create a timer in my ViewDidLoad method of my view-controller.

NSMethodSignature *sgn = [self methodSignatureForSelector:@selector(gameLoop:)];
NSInvocation *inv = [NSInvocation invocationWithMethodSignature: sgn];
[inv setTarget: self];
[inv setSelector:@selector(gameLoop:)];

NSTimer *t = [NSTimer timerWithTimeInterval: 1./30.
                                 invocation:inv 
repeats:YES];                                   

NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer: t forMode: NSDefaultRunLoopMode];


[[NSNotificationCenter defaultCenter] addObserver:self 
selector:@selector(statTapped:)                                          
name:@"statTapped"
object:nil];

Who and where can I deallocate this? If i try and do this from my dealloc it wont compile. Since t is not global.

-(void) dealloc
{
if (t) 
{
    [t invalidate];
    [t release];
    t=Nil;
}
}

Thanks, Code

+1  A: 

Make the NSTimer a property of your UIViewController. Release the timer in your UIViewController's dealloc method.

@property(nonatomic,retain) NSTimer *t;
Vivi
Also make it an instance variable
ckrames1234
Should have mention it as well yeah :)
Vivi
@ckrames: That's not necessary if the code only has to run on the modern Objective-C runtime. Apple made instance variables optional.
Georg
+2  A: 

The simplest way is to just store it in your instance with a property:

@property(retain) NSTimer *gameUpdater;

viewDidLoad:

self.gameUpdater = [NSTimer timerWithTimeInterval:1.0 / 30.0
                                       invocation:inv
                                          repeats:YES];

You should invalidate the timer when you don't need it anymore. (Unless it has to keep running until you quit the application anyway. In that case there's no point in invalidating it.)

It's a bad idea to do that in -dealloc because:

  • Apple might add garbage collection to cocoa touch at some later point. If that happens, dealloc won't get called anymore. That's part of the reason why you shouldn't do anything besides releasing objects in dealloc.

  • You're UIViewController might be retained somewhere else, in which case dealloc won't be called where expected as well. This might not be the case at the moment, but when you add additional functionality to your application suddendly you might need this functionality.

A good place to invalidate your timer might be in an action of the button called "pause" or similar.

Releasing the timer can still be done in -dealloc. Invalidated timers don't retain their targets anymore.

Georg
Im still confused. If the timer is repetitive and self is the target then how the dealloc is going to be called unless the timer is invalidated? How can you invalidate it in dealloc? And from which version of iPhone OS we have garbage collector?
taskinoor
@taskinoor: NSInvocation doesn't retain its target. I don't know if iOS ever gets a garbage collector. It's just good to be prepared and *-dealloc* isn't the place to do much cleaning up anyway.
Georg
Thanks Georg. I missed the difference between NSInvocation and scheduledTimerWithTimeInterval.
taskinoor
I'm confused now since a few people seems to be saying opposite things, Will the above code effectively release the timer when the dealloc gets called?
Code
@Code: Yes, in theory at least. The question was if *dealloc* gets called at all.
Georg
@taskinoor: To be fair, I wasn't certain and had to look it up myself after you pointed it out to me. :)
Georg
@Georg From what I gathered is that dealloc never gets called. Because its prevented by the timer being alive, and the timer will stay alive until dealloc gets called. So its circular. Still dnt know of the best solution.
Code
@Code, @taskinoor: I was wrong, just found this: *Note that an NSTimer object always instructs its NSInvocation object to retain its arguments; thus, you do not need to send retainArguments yourself.*
Georg
A: 

The method invalidate will cause the timer be removed from run loop. And by the rule of NACR (New, Alloc, Copy, Retain), the method -timerWithTimeInterval return an autorelease object, so you don't need to release again.

-(void) dealloc
{
   if (t) 
   {
     [t invalidate];
     //[t release];
     t=Nil;
   }
}
Toro