views:

212

answers:

1

Note: It's probably worth scrolling down to read my edit.

I'm trying to setup an NSTimer in a separate thread so that it continues to fire when users interact with the UI of my application. This seems to work, but Leaks reports a number of issues - and I believe I've narrowed it down to my timer code.

Currently what's happening is that updateTimer tries to access an NSArrayController (timersController) which is bound to an NSTableView in my applications interface. From there, I grab the first selected row and alter its timeSpent column. Note: the contents of timersController is a collection of managed objects generated via Core Data.

From reading around, I believe what I should be trying to do is execute the updateTimer function on the main thread, rather than in my timers secondary thread.

I'm posting here in the hopes that someone with more experience can tell me if that's the only thing I'm doing wrong. Having read Apple's documentation on Threading, I've found it an overwhelmingly large subject area.

NSThread *timerThread = [[[NSThread alloc] initWithTarget:self selector:@selector(startTimerThread) object:nil] autorelease];
[timerThread start];

-(void)startTimerThread
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
    activeTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateTimer:) userInfo:nil repeats:YES] retain];

    [runLoop run];
    [pool release];
}
-(void)updateTimer:(NSTimer *)timer
{
    NSArray *selectedTimers = [timersController selectedObjects];
    id selectedTimer = [selectedTimers objectAtIndex:0];
    NSNumber *currentTimeSpent = [selectedTimer timeSpent];

    [selectedTimer setValue:[NSNumber numberWithInt:[currentTimeSpent intValue]+1] forKey:@"timeSpent"];
}
-(void)stopTimer
{
    [activeTimer invalidate];
    [activeTimer release];
}

UPDATE

I'm still totally lost with regards to this leak. I know I'm obviously doing something wrong, but I've stripped my application down to its bare bones and still can't seem to find it. For simplicities sake, I've uploaded my applications controller code to: a small pastebin. Note that I've now removed the timer thread code and instead opted to run the timer in a separate runloop (as suggested here).

If I set the Leaks Call Tree to hide both Missing Symbols and System Libraries, I'm shown the following output:

The Leak with Missing Symbols and System Libraries hidden The Leak without Missing Symbols and System Libraries hidden

+1  A: 

If the only reason you are spawning a new thread is to allow your timer to run while the user is interacting with the UI you can just add it in different runloop modes:

NSTimer *uiTimer = [NSTimer timerWithTimeInterval:(1.0 / 5.0) target:self selector:@selector(uiTimerFired:) userInfo:nil repeats:YES];      
[[NSRunLoop mainRunLoop] addTimer:uiTimer forMode:NSRunLoopCommonModes];
sbooth
That is a much handier solution, thank you. I've just spent a bit of time reading up on runloops. Unfortunately, it doesn't seem to help with my leak. I've narrowed it down to (I believe) an issue in the updateTimer function. I believe it has something to do with how I'm updating the timeSpent variable within my NSArray of managed objects.
ndg
If the code you posted above is your actual updateTimer function, it looks OK to me. You do need to be careful not to release a timer once you've invalidated it, though.
sbooth
That is indeed my actual updateTimer function. I've updated the OP to summarize the issues I'm seeing (and to given an update on the code used).
ndg