NSMutableDictionary 内存泄漏 - 如何修复它而不导致应用程序崩溃?

发布于 2024-11-16 09:16:15 字数 1780 浏览 0 评论 0原文

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

calendarRequestLog 是单例对象中 MutableDictionary 类型的属性,只要应用程序运行,该属性就存在。这是 .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。

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

@编辑 我想我明白了。

当委托被释放时,我调用崩溃方法,这样我以后就不会每次意外调用委托。

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

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

...反过来,释放委托并调用崩溃方法。由于 calendarRequestLog 已删除委托,但尚未删除键,因此我们崩溃了。

好吧,我会以不同的方式解决这个问题。感谢所有的评论 - 谢谢你,我去别处看了!

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 = [calendarRequestLog 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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

死开点丶别碍眼 2024-11-23 09:16:15

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

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

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];
煮酒 2024-11-23 09:16:15

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

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];
无远思近则忧 2024-11-23 09:16:15

改写

calendarRequestLog = [[NSMutableDictionary alloc] init];

这个

self.calendarRequestLog = [NSMutableDictionary dictionary];

并尝试使用 property 代替 ivar

Write instead

calendarRequestLog = [[NSMutableDictionary alloc] init];

this

self.calendarRequestLog = [NSMutableDictionary dictionary];

and try to use property instead ivar

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文