核心数据:NSObjectID和NSTemporaryObjectID泄漏 [英] Core Data: NSObjectID and NSTemporaryObjectID leaks

查看:199
本文介绍了核心数据:NSObjectID和NSTemporaryObjectID泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我将应用程序发送到App Store之前,我喜欢检查内存泄漏和其他鱼饵。有一个核心数据问题,我似乎无法解决,所以我决定创建一个小测试应用程序来说明这个问题。





当我将一个实体保存在一个(子)NSManagedObjectContext中时,它被传播到其父NSManagedObjectContext。在此过程中,Core Data创建 _NSObjectID NSTemporaryObjectID 的内部实例。由于某些原因,这些实例被遗留下来,摆脱它们的唯一方法是重置父NSManagedObjectContext。



我的应用程序当然比这更复杂小测试应用和重置NSManagedObjectContext对我来说不是一个选项。



测试应用


$ b b

测试应用程序是一个基于单视图模板并选中CoreData选项的标准iOS应用程序。我使用objective-c保持它类似于我的生产应用程序。

   - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 
//初始化核心数据栈
self.persistentStoreCoordinator = [self persistentStoreCoordinator];

//创建一个私有上下文
self.rootContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
self.rootContext.persistentStoreCoordinator = self.persistentStoreCoordinator;

//创建子上下文
self.childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
self.childContext.parentContext = self.rootContext;

//创建一个人
[self.childContext performBlockAndWait:^ {
Person * person = [NSEntityDescription insertNewObjectForEntityForName:@PersoninManagedObjectContext:self.childContext];
person.name = @John Smith;
person.age = 30;

//保存人
[self.childContext save:nil];

//保存根上下文
[self.rootContext performBlockAndWait:^ {
[self.rootContext save:nil];
}];
}];

return YES;
}



当您使用仪器和分配仪器运行上面的代码时,您可以看到



您可以在这里找到完整的项目:



我尝试的东西



我尝试过 :... mergeChanges:YES] ,添加 @autoreleasepool 和/或 [context processPendingChanges] 里面的块,这一切都没有帮助。清除它的唯一方法是执行 [上下文重置] (大锤方法)。



找到其他人报告这个问题。
此博文似乎类似:



但是,我不知道我会关心,除非你看到很多这些,他们永远不会离开。我假定Core Data的内部(包括行缓存)有某种类型的对象缓存。



另一方面,我的Core Data使用已经改变了一点过去一两年。



除非是一个非常简单的应用程序,我几乎从不在子上下文中创建新对象。我将获取和修改它们,但如果我最终创建一个新的对象,我确保它是在兄弟的上下文中完成。



但是,如果你修改代码在初始保存之前,通过添加这一行(你有适当的错误处理 - 返回 BOOL

  NSArray * inserted = self.childContext.insertedObjects.allObjects; 
[self.childContext getsPermanentIDsForObjects:inserted error:& error];

你应该得到类似这样的仪器报告,它显示所有创建为瞬态的对象...





因此,我不一定认为是永久性泄漏,因为一旦我强制上下文转换为永久ID,对象就会消失。但是,谁知道它们保存这些对象ID对象的时间有多长。



一般来说,当我在包含层次结构的上下文中创建对象时,第一(出于很多原因)。但是,正如我之前所说,我通常在直接创建持久化存储的上下文中创建新对象(因为我不得不处理与层次结构临时对象ID相关的其他问题,特别是在使用多个非相关上下文时) / p>

Before I send my app to the App Store I like to check it for memory leaks and other fishy stuff with instruments. There is one Core Data issue that I can't seem to solve, so I've decided to create a small test app to illustrate the problem.

What's the problem?

When I save an entity in a (child) NSManagedObjectContext it is propagated to its parent NSManagedObjectContext. During this process Core Data creates internal instances of _NSObjectID and NSTemporaryObjectID. For some reason these instances are left behind and the only way to get rid of them is to reset the parent NSManagedObjectContext.

My app is of course a lot more complex than this little test app and resetting the NSManagedObjectContext isn't an option for me.

Test app

The test app is a standard iOS app based on the single view template with the CoreData option checked. I've used objective-c to keep it similar to my production app.

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Initialize the Core Data stack
    self.persistentStoreCoordinator = [self persistentStoreCoordinator];

    // Create the a private context
    self.rootContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
    self.rootContext.persistentStoreCoordinator = self.persistentStoreCoordinator;

    // Create a child context
    self.childContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType];
    self.childContext.parentContext = self.rootContext;

    // Create a person
    [self.childContext performBlockAndWait:^{
        Person *person = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:self.childContext];
        person.name = @"John Smith";
        person.age = 30;

        // Save the person
        [self.childContext save:nil];

        // Save the root context
        [self.rootContext performBlockAndWait:^{
            [self.rootContext save:nil];
        }];
    }];

    return YES;
}

When you run the code above with instruments and the allocations instrument you can see that Core Data leaves some stuff behind.

You can find the full project here: https://github.com/Zyphrax/CoreDataLeak

Things I've tried

I've tried things like [context refreshObject:... mergeChanges:YES], adding @autoreleasepool and/or [context processPendingChanges] inside the blocks, it all doesn't help. The only way to get it clean is to do a [context reset] (sledgehammer approach).

It's hard to find other people reporting this problem. This blog post seems similar:
http://finalize.com/2013/01/04/core-data-issues-with-memory-allocation/

I hope you guys can help me with this.

解决方案

Here is what I see, which is very similar to yours...

However, I don't know that I would be concerned, unless you see lots of these, and they never go away. I assume the internals of Core Data (including the row cache has) some sort of object caching going on.

On the other hand, my Core Data usage has changed a bit over the past year or two.

Unless it is a very simple app, I almost never create new objects in a child context. I will fetch and modify them, but if I end up creating a new object, I make sure that is done in a sibling context.

However, if you modify your code slightly, by adding this line (with your appropriate error handling - it returns BOOL) before the initial save...

NSArray *inserted = self.childContext.insertedObjects.allObjects;
[self.childContext obtainPermanentIDsForObjects:inserted error:&error];

you should get something like this instruments report, which shows all objects created as being transient...

Thus, I don't necessarily think it is a permanent leak, because once I force the context to convert to a permanent ID, the objects go away. However, who knows how long they keep those object ID objects cached.

In general, when I create objects in a context that contains a hierarchy, I will always obtain permanent IDs first (for many reasons). However, as I said earlier, I usually create new objects in a context that is directly created to the persistent store (because I have had to deal with other issues related to hierarchies temporary object IDs, especially when using multiple non related contexts).

这篇关于核心数据:NSObjectID和NSTemporaryObjectID泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆