【问题标题】:In Objective C why are my core data objects never being deallocated?在 Objective C 中,为什么我的核心数据对象永远不会被释放?
【发布时间】:2011-03-20 19:18:18
【问题描述】:

我在释放 m 个核心数据对象时遇到了很多麻烦。我什至尝试了我能想到的最简单的测试,我观察了保留计数,它似乎总是比我预期的要高。我还在核心数据对象的 dealloc 例程上设置了一个断点,它似乎没有被调用(至少不会被调用,除非我特别添加了其他版本)。

顺便说一句,我肯定有 [managedObjectContext setRetainsRegisteredObjects:NO],所以这不是问题。

这是一个我试过但不起作用的例子:

MobileObject *obj = [NSEntityDescription insertNewObjectForEntityForName:@"MobileObject" inManagedObjectContext:managedObjectContext];

NSLog(@"Object count after creation %d", [obj retainCount]);

NSError *error;
[managedObjectContext save:&error];

NSLog(@"Object count after saving %d", [obj retainCount]);

每条日志消息都打印出“2”。 Dealloc 永远不会被调用。我希望保存会导致对象被释放(或自动释放),因为核心数据应该意识到它不需要保留。在这种情况下,如果有两个自动释放(一个来自创建,一个来自保存),则保留计数 2 是有意义的,但情况似乎并非如此。如果我添加

[obj release] 

在我的测试结束时,dealloc 例程将被正确调用,但我很困惑为什么我需要这个版本。

【问题讨论】:

    标签: objective-c core-data memory-management


    【解决方案1】:

    保存 CoreData 上下文在逻辑上与释放NSManagedObject 相关。

    在大型程序中,在程序运行时始终拥有托管对象上下文 (moc) 是很常见的。对象被添加到反映用户操作的上下文中或从上下文中删除,并且有时还会保存一次上下文,以便内存中的上下文与您在文件中的内容同步。但是在这种情况下,保存上下文并不意味着你已经完成了上下文;您仍然保留上下文并像保存之前一样使用它。因此,保存并不意味着释放对象。

    所以,如果你想释放你保留的对象,你需要显式释放它们。

    但是在这种情况下,insertNewObjectForEntityName:inManagedObjectContext: 返回一个 autoreleased 对象作为written here。因此,除非您明确保留它,否则您不拥有该对象。如果你没有保留,你不应该释放它。它已发布,并在适当时自动调用 dealloc

    请注意,您永远不应依赖retainCount 来查看发生了什么。对于一个简单的对象,retainCount 的数量会符合我们的预期,但是对于像 NSManagedObject 这样复杂的东西,框架本身需要跟踪很多事情,所以可能会做很多 @987654329 @幕后。例如,即使您没有显式保留一个对象,它也可能与您拥有的另一个对象存在关系;或者 CoreData 可能只是决定将对象保留在内存中以缓存它。

    唯一要记住的是遵守标准所有权规则。如果你alloc/initretain,你稍后releaseautorelease 它。

    在评论中回答你的问题,让我在这里陈述基本原则: 如果一个对象x需要另一个对象axretainsa。当x 使用完ax releases a。每个对象x 都应遵循此过程,无论x 是您编码的对象,还是Apple 框架提供的对象。如果每个对象都遵循这个原则,就没有泄漏。因此,您看不到的 Apple 代码如下所示。您的代码也应该遵循这一点。

    这回答了你的问题:

    当我将子对象“添加”到父对象时,父对象是否会自动保留我添加的对象?

    是的。父母需要它,所以它保留它。

    如果我随后释放父对象,它会释放子对象还是我必须明确地这样做?

    是的,父级确实释放了子级,因为当父级为dealloced 时,它完成了对子级的使用,因此子级为releaseed。

    这些点通常不会写在各个方法的文档中,因为作为规则,每个 API 都遵循这个基本的内存管理原则,因此无需详细说明。

    我们鼓励您阅读Memory Manegement Rules

    【讨论】:

    • 似乎无法判断我的程序是否正确。例如,我的对象之间有一些复杂的关系,当我将子对象“添加”到父对象时,父对象是否会自动保留我添加的对象?如果我然后释放父对象,它将释放子对象还是我必须明确地这样做?我非常担心不小心抓住我不再需要的物品。我很惊讶任何人都可以编写一个没有至少一次内存泄漏的 Objective C 应用程序。
    • @Mike -- 管理内存所需要做的就是学会将对象的初始化与释放配对。由于每个类都将自己的内存作为一个模块进行管理,因此您可以拥有无​​限数量的嵌套对象,所有这些对象都可以轻松管理内存。诀窍在于学习区分初始化和引用。您必须学会区分在拥有对象内创建新对象的方法和仅返回在其他地方创建的对象的地址的方法。
    • 为您的其他问题添加了答案。
    【解决方案2】:

    Core Data 会管理自己的内存,您无需担心。只需遵循保留/释放规则,让 Core Data 自行处理。

    当您测试泄漏时,是您需要确保您的代码遵守规则的时候。

    Core Data 可以并且将在您使用完对象后将其保留很长时间。只有在内存不足的情况下才会释放它们。

    如果你想强制释放内存(例如当你在 iOS4 上进入后台时),你应该在你的 NSManagedObjectContext 上调用 -reset,这将强制 Core Data 清除尽可能多的内存。但即便如此,也不能保证 NSManagedObject 将被释放。但是,它会出错。

    简短的回答……别担心。

    【讨论】:

      【解决方案3】:

      当您在 Core Data 中使用托管对象时,您通常不会使用 retainrelease,因为 Core Data 会为您处理这些事情。如果你有一个你知道你不需要使用一段时间的对象,你可以重新故障它(这将把它剥离成一个占用更少内存的骨架。要重新故障 NSManagedObject 确保对它的任何更改都有已保存并且来自其他上下文的任何更改(如果有)已合并,然后只需调用 [managedObjectContext refreshObject:objectToFault mergeChanges:NO];

      【讨论】:

        猜你喜欢
        • 2011-04-17
        • 1970-01-01
        • 1970-01-01
        • 2011-05-26
        • 1970-01-01
        • 1970-01-01
        • 2011-11-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多