NSMutableDictionary 内存泄漏 - 如何修复它而不导致应用程序崩溃?
我一定是误解了一些内存管理规则,因为当我尝试修复内存泄漏时,应用程序崩溃了。让我向您展示一些代码:
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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您是否尝试在获取时保留,以便在您使用它时没有人释放您的对象?
Did you try retaining when fetching so nobody releases your object while you're using it?
常见的做法如下,因为您已经保留在 .h 文件中:
另外,我不太明白为什么您要保留在这里:
为什么不将其更改为:
Common practice is the following, because you already retain in the .h file:
Also, I don't really understand why you would retain here:
Why not just change that to:
改写
这个
并尝试使用 property 代替 ivar
Write instead
this
and try to use property instead ivar