开发者

NSMutableDictionary memory leak - how do I fix it without crashing the App?

I must have misunderstood some of the memory management rules, because when I try to fix a memory leak, the App crashes. Let me show you some code:

calendarRequestLog is a property of type MutableDictionary in a singleton object, that exists as long as the App runs. Here's the declaration in the .h file:

@property (nonatomic, retain, readonly) NSMutableDictionary *calendarRequestLog;

I allocate it with (in init):

calendarRequestLog = [[NSMutableDictionary alloc] init];

I fill it with this (notice the retain, that creates the memory leak):

[calendarRequestLog setObject:[[NSMutableArray arrayWithObject:delegate] retain] forKey:date];

I sometimes access it with this:

NSMutableArray* delegates = [calendarRequestLog objectForKey:date];
if(delegates != nil) {
   // add delegates
}

I empty it with this:

NSMutableArray* delegates = [cale开发者_运维百科ndarRequestLog objectForKey:date];    
if(delegates != nil) {
    for (id <ServerCallDelegate> delegate in delegates) { … }

    // clear the request from the log
    [calendarRequestLog removeObjectForKey:date];
}

Here's the code that crashes when I remove the retain above:

NSMutableArray* delegates = [calendarRequestLog objectForKey:date];
if(delegates != nil) {
    if([delegates containsObject:delegate]) // crash
        [delegates removeObject:delegate];
}

It crashes because delegates is deallocated but not nil. To be more precise, I get an EXC_BAD_ACCESS Exception.

All these methods may be called in different orders or multiple times.

I cannot figure out, why this happens. I thought, collections are supposed to retain their objects - as this array-object (delegates) is still in the collection, it should not be deallocated. Other code cannot be responsible, I showed you all occurrences of calendarRequestLog.

I appreciate all the help I can get!

@Edit I think I got it.

I call the crashing method when the delegate gets deallocated, so that I do not call the delegate per accident later.

But: I retain the delegates in my calendarRequestLog, so it cannot get deallocated as long as this doesn't get called:

    // clear the request from the log
    [calendarRequestLog removeObjectForKey:date];

...which in turn, deallocates the delegate and calls the crashing method. As the calendarRequestLog has removed the delegates, but not yet the key, we crash.

Ok, I will solve this differently. Thanks for all the comments - thanks to you, I looked elsewhere!


Did you try retaining when fetching so nobody releases your object while you're using it?

NSMutableArray* delegates = [[calendarRequestLog objectForKey:date] retain];
if(delegates != nil) {
     if([delegates containsObject:delegate]) // crash
          [delegates removeObject:delegate];
}
[delegates release];


Common practice is the following, because you already retain in the .h file:

//create local instance, then copy that to the class wide var
NSMutableDictionary *_calendarRequestLog = [NSMutableDictionary alloc] init];
self.calendarRequestLog = _calendarRequestLog;
[_calendarRequestLog release];

Also, I don't really understand why you would retain here:

[calendarRequestLog setObject:[[NSMutableArray arrayWithObject:delegate] retain] forKey:date];

Why not just change that to:

[calendarRequestLog setObject:[NSMutableArray arrayWithObject:delegate] forKey:date];


Write instead

calendarRequestLog = [[NSMutableDictionary alloc] init];

this

self.calendarRequestLog = [NSMutableDictionary dictionary];

and try to use property instead ivar

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜