views:

72

answers:

3

I'm very new to Objective-C and I'm trying to develop an iPhone app. My problem is I get "message sent to deallocated instance 0x3d54830" error when I use an object inside an NSTimer. When I don't use an NSTimer, I can use the object just fine. For example:

//These can be any objects.  Le't say I have a Song class and a SongReader class in the header file SongTest.h
Song *song;
SongReader *reader;

NSTimer *timer;

- (void)justDoIt;


//In the implementation file SongTest.m
- (void)viewDidLoad {
    reader = [[SongReader alloc] init];
    song = [reader readSong];

    timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(justDoIt) userInfo:nil repeats:YES];
}

- (void)justDoIt {
    NSLog(@"This is a song integer property: %d", song.wordCount);
}

- (void)dealloc {
    [reader release];
    [super dealloc];
}

The song object inside the justDoIt method/selector/message is already deallocated according to the debugger. What am I doing wrong? Even if I do it like:

song = [[reader readSong] retain]; //or
[song retain]; //or
[reader retain];

The object still gets deallocated unexpectedly. Again, the problem only happens when I use NSTimer. It's like the object gets deallocated even before the timer fires.

+2  A: 

The problem may be the target of the NSTimer call (i.e. "self"). Thus the message, "justDoIt", is sent to a deallocated instance, the object represented as "self" in your code.

Is the controller instance deallocated before the timer is fired?

Ken Pespisa
Thanks for your reply. The controller instance is not deallocated. In fact, all other instance variables can be accessed inside the "justDoIt" message. It's just this particular object I'm having problems with.
tonex
Hi, Ken. I really appreciate your help. I found the answer - see dodgio's reply. Thanks!
tonex
+1  A: 

Are you retaining your SongTest object? You don't show that part of the code, but if it's autoreleased, it will be deallocated by the time the timer fires. In fact, that's really what the error message is indicating:

"message sent to deallocated instance 0x3d54830"

You're creating the timer to send a message to "self" which is the SongTest object.

Also, you do need to retain the song:

song = [[reader readSong] retain];

if you've coded -readSong according to the standard Cocoa conventions.

dodgio
Hey, dodgio. I know I said "song = [[reader readSong] retain]" didn't work for me but I tried it again after you said so. Now, it works. Also, I release SongTest explicitly. I didn't have to retain it.Thanks, man!
tonex
A: 

You should use properties to keep these sort of errors from cropping up. If you define song as...

@property(nonatomic, retain)  Song *song;
...
@synthesize song;

...and use it like this...

self.song=[reader readSong];

... objective-c manages the retention and release for you until you call dealloc.

Unrelated to you main problem, the method called by the timer should be of the form...

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

...or it might not always be called properly.

TechZen
You're probably right TechZen. I didn't want to use properties because I'm thinking it's more resource intensive. But now I see your point. I'll also try this one out.
tonex