cpjolicoeur
cpjolicoeur

Reputation: 13106

memory access error when releasing a newly created object

I'm having an issue understanding why releasing an object that I just created is causing a memory access error in my application.

I'm creating a bunch of objects and adding them to an NSMutableArray. After I add them to the array, I release them. The first time the function runs, things go smoothly. The second time the function runs, releasing the object crashes the application and I'm not sure why.

Here is the part of the function in question (full project source is available here: http://github.com/cpjolicoeur/echowaves-notifier-osx)

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    [connection release];
    NSString *responseString = [[NSString alloc] initWithData:echowaves.responseData encoding:NSUTF8StringEncoding];
    [echowaves.responseData release];

    ...more code...

    [[echowaves updatedConvos] removeAllObjects];
    NSDictionary *dictionary = [responseString JSONValue];
    if ( [dictionary count] ) {
        for (NSDictionary *subscription in dictionary ) {
            UpdatedConvo *convo = [[UpdatedConvo alloc] initWithConvoName:[[subscription objectForKey:@"subscription"] objectForKey:@"convo_name"]
                                                                 convoURI:[[subscription objectForKey:@"subscription"] objectForKey:@"conversation_id"]
                                                              unreadCount:[[[subscription objectForKey:@"subscription"] objectForKey:@"new_messages_count"] integerValue]];


            [[echowaves updatedConvos] addObject:convo];
            [convo release];  // THIS LINE CAUSES CRASH 2ND TIME THROUGH
        }
    } else {

        ...more code....

    }
}            

The app crashes on the [convo release] line the 2nd time through the function. Since the convo object is created two lines before it I'm not sure why.

I'm under the impression that the UpdatedConvo *convo = [[UpdatedConvo alloc] initWithConvoName...] call will create the object and give it a retain count of 1. Then when I add the object to the [echowaves updatedConvos] NSMutableArray object, it should bump the retain count by 1 (now count is 2). I'm done with that "temporary" convo object so I then release it, which should move its retain count back down to 1, correct??

What am I missing here?

To get the app to run successfully, I have to comment out the [convo release] line. I don't know why though, and I feel that this is probably giving me a slow memory leak since that newly created UpdatedConvo object isn't being freed from memory properly.

Upvotes: 1

Views: 183

Answers (2)

Thomas Zoechling
Thomas Zoechling

Reputation: 34253

As e.James already mentioned: UpdatedConvo seems to be your problem.
I looked at the github project you posted. Probably you are over-releasing in UpdatedConvo:

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

You are neither creating, nor retaining ewURI and ewName in the class.
So you shouldn't release it there.

Update: Fixed a misleading typo (I wrote "releasing" instead of "retaining" in last sentence)

Update2: I would run your code through Instruments.app with the "Zombie" and "Leaks" presets.
If you haven't tried Instruments before, this is a great opportunity to see it at work.

Upvotes: 1

James Eichele
James Eichele

Reputation: 119144

Your method should work. It is a common pattern to create an object, add it to a dictionary, and then release it.

The fact that it doesn't work suggests that the problem is elsewhere. The first place to check is in the UpdatedConvo class itself. Does it do anything fancy in its dealloc method?

edit: The problem is definitely in UpdatedConvo. You assign your instance variables (with =) in your init method:

- (id)initWithConvoName:(NSString *)convoName
               convoURI:(NSString *)convoURI
            unreadCount:(int)updatesCount 
{
    if ( self = [super init] ) {
        ewURI = convoURI;
        ewName = convoName;
        newMessagesCount = updatesCount;
    }
    return self;
}

But then you call release on them in dealloc:

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

Using = in the init method does not increase the retain count, so when you release them, you are actually reducing the retain count too far.

Upvotes: 3

Related Questions