iOS / ManagedObjectContext 中的内存管理

Posted

技术标签:

【中文标题】iOS / ManagedObjectContext 中的内存管理【英文标题】:Memory management in iOS / ManagedObjectContext 【发布时间】:2011-01-16 11:25:39 【问题描述】:

看来我不了解 Objective C 中的内存管理...唉。

我有以下代码(请注意,在我的例子中,placemark.thoroughfareplacemark.subThoroughfare 都填充了有效数据,因此 if-conditions 将是 TRUE

item 绑定到 ManagedObjectContextitem 中的托管变量(例如 place)具有使用 @dynamic 创建的 setter/getter。因此,声明是

@property (nonatomic, retain) NSString *place;
@dynamic place;

稍后在代码中,在 ReverseGeocoderDelegate 中,我访问它:

- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark 

if (placemark.thoroughfare) 
    [item.place release];
    item.place = [NSString stringWithFormat:@"%@ ", placemark.thoroughfare];        
 else 
    [item.place release];
    item.place = @"Unknown Place";

if (placemark.thoroughfare && placemark.subThoroughfare) 
// *** problem is here ***
    [item.place release];
    item.place = [NSString stringWithFormat:@"%@ %@", placemark.thoroughfare , placemark.subThoroughfare];

如果我没有在代码中的标记位置释放item.place,Instruments 会发现那里存在内存泄漏。如果我这样做了,一旦我尝试在违规方法之外访问item.place,程序就会崩溃。

有什么想法吗?

【问题讨论】:

粘贴place属性的声明以及它的setter方法的定义(如果有的话)会很有用。 你的意思是你用@synthesize生成你的getter/setter? 我使用了@dynamic,据我所知,这对于与 ManagedObjectContext 绑定的属性来说是正确的,就像我的情况一样 【参考方案1】:

首先,我会改变这样的逻辑:

NSString *newPlace = nil;

if (placemark.thoroughfare && placemark.subThoroughfare) 
    newPlace = [NSString stringWithFormat:@"%@ %@", placemark.thoroughfare , placemark.subThoroughfare];

else 
    if (placemark.thoroughfare) 
        newPlace = [NSString stringWithFormat:@"%@ ", placemark.thoroughfare];
    
    else 
        newPlace = @"Unknown Place";
    


item.place = newPlace;    // Either nil of valid string can be assigned to

很多人不推荐使用 release 来简单地重新初始化指针。如果是为了节省一些内存,您不必这样做。

你之前的逻辑确实释放了两次。 release 最初所做的只是减少retainCount。如果为 0,则对象被释放。对象在其retainCount 为0 之前不会被释放。

假设您的 item 具有属性 retain 并且由于 stringWithFormat: 返回 autoreleased 字符串,因此在第二个版本中,您试图释放将要发布的内容无论如何都要autoreleased

多次清除对象的最佳方法是简单地将nil 分配给它。

【讨论】:

我根据你的建议改了,但仪器仍然在奇怪的地方显示泄漏。因为整个项目太大了,我有一种必须自己解决的印象。感谢您的帮助,是的:我将 nil 分配给我的保留属性,而不是释放它们。似乎更安全,应该有同样的效果。 我很高兴我的建议很有帮助。希望你修复所有的漏洞!【参考方案2】:

一个起点是重新阅读属性,因为您不需要在任何地方执行“[item.place release]”。所以你可以删除它们。运行时创建的用于启用该属性的动态代码会自动处理释放之前分配给它的任何内容。

另外,[NSString stringWithFormat:... 创建了一个自动释放对象(不确定您是否知道 :-),这意味着如果您手动管理变量(不是属性)的内存,那么您将不得不保留/释放它.但是因为你使用的是属性,所以你没有。

我不明白为什么仪器会发现内存泄漏。也许一些更高的代码与它有关。例如,如果你去了item.place = [NSString alloc] initWith...];,那么我认为你会需要它。

我怀疑崩溃是因为版本导致保留计数为零并触发 exec 错误访问错误。

希望对您有所帮助。

【讨论】:

是的,我的问题描述应该更详细一点。添加了更多信息。 好。但我认为我的 cmets 仍然适用。看起来你“过度管理”。首先删除所有版本。托管对象上下文处理属性代码并将正确管理它。 ‘但是因为你使用的是属性,所以你不使用。’ → 嗯,并非总是如此。如果它是一个 assign 属性(并且 assign 是一个默认属性属性),那么他仍然需要管理内存,即使这不是一个好主意。此外,他可能有一个自定义设置器。 @Bavarious - 是的。我忘了提到我假设属性是使用保留属性设置的。刚刚检查了我的一个项目,核心数据生成的类在属性上设置了保留。所以希望我的cmets是正确的。 :-) 我没有自定义设置器。我使用@dynamic 生成。但是如果所有的 cmets 都是正确的,那么泄漏在哪里呢? Instruments 将我指向上面的位置。

以上是关于iOS / ManagedObjectContext 中的内存管理的主要内容,如果未能解决你的问题,请参考以下文章

没有上下文的CoreData关系设置?

如何使用非 nil parentContext 创建 NSManagedObjectContext?

self.managedObjectContext 和 managedObjectInstance.managedObjectContext 有啥区别?

SwiftUI - 核心数据从按钮中删除项目

在后台线程上将 XML 解析为 CoreData 以不锁定 UI

{python之IO多路复用} IO模型介绍 阻塞IO(blocking IO) 非阻塞IO(non-blocking IO) 多路复用IO(IO multiplexing) 异步IO