【问题标题】:NSMutableDictionary memory leak - how do I fix it without crashing the App?NSMutableDictionary 内存泄漏 - 如何在不崩溃应用程序的情况下修复它?
【发布时间】:2011-06-17 07:24:08
【问题描述】:

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

calendarRequestLog 是单例对象中 MutableDictionary 类型的属性,只要应用程序运行,它就存在。这是 .h 文件中的声明:

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

我用 (in 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];
}

它崩溃是因为委托被释放但不是 nil。更准确地说,我得到了一个 EXC_BAD_ACCESS 异常。

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

我不知道为什么会这样。我想,集合应该保留它们的对象——因为这个数组对象(委托)仍然在集合中,它不应该被释放。其他代码不负责任,我给你展示了所有出现的calendarRequestLog。

感谢我能得到的所有帮助!

@编辑 我想我明白了。

我在委托被解除分配时调用崩溃方法,这样我以后就不会在每次事故中调用委托。

但是:我将代表保留在我的 calendarRequestLog 中,因此只要不调用它就无法释放它:

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

...依次释放委托并调用崩溃方法。由于 calendarRequestLog 已经删除了代表,但还不是 key,所以我们崩溃了。

好的,我会以不同的方式解决这个问题。感谢所有 cmets - 感谢您,我在别处寻找!

【问题讨论】:

  • 我没有看到明显的问题。正如您所怀疑的,在 [calendarRequestLog setObject:[[NSMutableArray arrayWithObject:delegate] retain] forKey:date];保留不是必需的。我认为问题出在您未包含的某些代码中。
  • 如果没有-retain,它应该可以工作。您是否绝对确定不会在代码的某些部分中释放该数组,例如[delegates release]?
  • 我确定 - delegates 始终是一个局部变量,我发布了所有访问 calendarRequestLog 的函数的内容。
  • 也许可以提供更多关于崩溃的代码。你使用 delegate 变量...你能保证它总是一个有效的对象还是 nil 吗?
  • @Cit 如果你发现了问题,你应该写下你的解决方案作为答案,并将其标记为下面的答案。

标签: ios iphone objective-c nsmutabledictionary


【解决方案1】:

您是否尝试在获取时保留,以便在您使用时没有人释放您的对象?

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

【讨论】:

    【解决方案2】:

    常见的做法如下,因为你已经在 .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];
    

    【讨论】:

    • 因为代码那样崩溃了。不过谢谢你的建议!
    【解决方案3】:

    改写

    calendarRequestLog = [[NSMutableDictionary alloc] init];
    

    这个

    self.calendarRequestLog = [NSMutableDictionary dictionary];
    

    并尝试使用属性而不是 ivar

    【讨论】:

    • 在第一种情况下,对象被隐式保留。在第二个中,字典在创建时自动释放并使用访问器保留。两者都是一样的。但首选第一个,因为在 initdealloc 方法中不鼓励调用 self
    猜你喜欢
    • 1970-01-01
    • 2018-04-04
    • 1970-01-01
    • 2011-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-09-20
    相关资源
    最近更新 更多