NSManagedObject子类的意外自定义init方法行为

时间:2013-02-04 23:14:21

标签: objective-c core-data restkit

我想以简单的方式创建一个NSManagedObject子类的实例:Library *library = [[Library alloc] init]所以我像这样覆盖init方法。

- (instancetype)init
{

    NSManagedObjectContext *managedObjectContext = [[NSManagedObjectContext alloc] 
                               initWithConcurrencyType:NSMainQueueConcurrencyType];
    managedObjectContext.parentContext = [RKManagedObjectStore 
                                      defaultStore].mainQueueManagedObjectContext;

   NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"Library" 
                                       inManagedObjectContext: managedObjectContext];

   self = [super initWithEntity:entityDescription  
                  insertIntoManagedObjectContext:managedObjectContext];

   return self;
}

在视图中,我使用Library *library = [[Library alloc] init]创建新实例,这非常有用。现在我需要将Book对象添加到与它有关系的Library。因此,新的Book实例应与其父{ - 1}}位于同一managedObjectContext。要正确实例化Library,我需要获取Book的managedObjectContent:Library返回[library managedObjectContent]。几个小时后,我有一个解决方法:

nil

在GTObjectManager中,我只使用与旧的init方法相同的代码:

- (instancetype)init
{

    NSManagedObjectContext *managedObjectContext = [GTObjectManager newManagedObjectContext];

   NSEntityDescription *entityDescription = [NSEntityDescription entityForName:@"City" 
                                       inManagedObjectContext: managedObjectContext];

   self =  [super initWithEntity:entityDescription  
                  insertIntoManagedObjectContext:managedObjectContext];

   return self;
}

现在,在实例化+ (NSManagedObjectContext *)newManagedObjectContext { NSManagedObjectContext *managedObjectContext = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSMainQueueConcurrencyType]; managedObjectContext.parentContext = [RKManagedObjectStore defaultStore].mainQueueManagedObjectContext; return managedObjectContext; } 之后调用Library *library = [[Library alloc] init]不会返回[library managedObjectContext]。所以澄清一下:如果在nil方法中创建managedObjectContext,我在实例化后无法获取它。如果在init方法之外创建managedObjectContent,我可以在实例化后获取它。

我无法解释这种行为。这是init方法的行为吗?我正在使用ARC,它是某种ARC行为吗?

1 个答案:

答案 0 :(得分:1)

在您的第一个 init函数中,您创建一个本地managedObjectContext对象并使用它来创建托管对象。 托管对象不保留其上下文,因此managedObjectContext是对象的唯一强引用。 ARC添加代码以在函数末尾释放此引用,并且由于它是唯一的引用,因此将释放托管对象上下文。

如果您将以下代码添加到init函数(self = [super initWithEntity:...]之后),则可以观察到此行为:

NSLog(@"%@", [self managedObjectContext]);
// Output: <NSManagedObjectContext: 0x100134a00>
managedObjectContext = nil;
NSLog(@"%@", [self managedObjectContext]);
// Output: (null)

如您所见,如果上下文已被释放,则向托管对象询问其上下文将返回nil

在您的第二个 init函数中,应该完全相同,我在测试程序中观察到完全相同的行为。但这取决于如何调用返回新上下文的实用程序方法。

在您的代码示例中,它被称为newManagedObjectContext。以new...开头的方法返回保留的对象,并在init函数结束时释放。因此,您的两个init函数之间应该没有区别。

然而,如果调用实用方法,例如getManagedObjectContext,然后返回(粗略地说)一个自动释放的对象。此对象可能存在的时间更长,直到当前的自动释放池被销毁。

也许这就解释了为什么如果在实用程序方法中创建上下文,您的代码似乎有效。

结论: 如果以后需要这些对象,创建本地临时上下文来创建对象是没有意义的。托管对象存在于上下文中,如果上下文被破坏,则无法再使用这些对象。

您必须先决定要使用哪个上下文,然后在该上下文中创建对象及其关系。