NSMutableDictionary内存泄漏 - 如何在不崩溃应用程序的情况下修复它?

时间:2011-06-17 07:24:09

标签: ios iphone objective-c nsmutabledictionary

我一定误解了一些内存管理规则,因为当我尝试修复内存泄漏时,App崩溃了。让我给你看一些代码:

calendarRequestLog是单个对象中MutableDictionary类型的属性,只要App运行就存在。这是.h文件中的声明:

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

我用(在init中)分配它:

calendarRequestLog = [[NSMutableDictionary alloc] init];

我用它填充它(注意保留,这会造成内存泄漏):

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

我有时会用它来访问它:

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

我把它清空:

NSMutableArray* delegates = [calendarRequestLog objectForKey:date];    
if(delegates != nil) {
    for (id <ServerCallDelegate> delegate in delegates) { … }

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

以下是删除上面的保留时崩溃的代码:

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

崩溃是因为代理被解除分配但不是零。更准确地说,我得到一个EXC_BAD_ACCESS异常。

所有这些方法可以按不同顺序或多次调用。

我无法弄清楚,为什么会这样。我认为,集合应该保留它们的对象 - 因为这个数组对象(委托)仍然在集合中,所以它不应该被释放。其他代码不负责任,我向你展示了所有出现的calendarRequestLog。

我感谢所有帮助!

@Edit 我想我明白了。

当委托被取消分配时,我调用了崩溃方法,以便我不会在以后的事故中调用委托。

但是:我在calendarRequestLog中保留了委托,所以只要不调用它就不能取消分配:

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

...反过来,取消分配委托并调用崩溃方法。由于calendarRequestLog已经删除了代理,但还没有删除密钥,我们崩溃了。

好的,我会以不同的方式解决这个问题。感谢所有评论 - 多亏了你,我看了看其他地方!

3 个答案:

答案 0 :(得分:0)

您是否尝试在抓取时保留,以便在您使用它时没有人释放您的物体?

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

答案 1 :(得分:-1)

通常的做法如下,因为您已经保留在.h文件中:

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

另外,我真的不明白为什么你会留在这里:

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

为什么不将其改为:

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

答案 2 :(得分:-3)

改为写

calendarRequestLog = [[NSMutableDictionary alloc] init];

self.calendarRequestLog = [NSMutableDictionary dictionary];

并尝试使用属性而不是ivar