在后台线程中恢复NSManagedObject关系

时间:2012-03-27 08:02:25

标签: ios core-data nsmanagedobject nsmanagedobjectcontext nsoperation

我正在通过Core Data开发一个应用程序,我需要在后台线程中执行一些计算,以根据特定的NSManagedObject创建一个xml文件。

在文档之后,我设置了NSOperation子类。该类具有如下属性:

@property (nonatomic, retain) NSArray* objectIDs;

其中objectIDs是托管对象ID的数组(类型为NSManagedObjectID)。根据文档,这是必要的:NSManagedObject不是线程安全的。

main子类的NSOperation内,我正在执行以下操作:

NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

NSManagedObjectContext *exportContext = [[NSManagedObjectContext alloc] init];
[exportContext setPersistentStoreCoordinator:[self persistentStoreCoordinator]];

for (NSManagedObjectID* objectID in self.orderObjectIDs) {

    NSError* error = nil;
    Order* order = (Order*)[exportContext existingObjectWithID:objectID error:&error];

    // order.someRelationship is fault here...

    // Create XML file here...
}

[exportContext reset];
[exportContext release], exportContext = nil;

[[NSNotificationCenter defaultCenter] postNotificationName:kRegisterComplete object:self];

[pool drain];
pool = nil;

for循环内我使用existingObjectWithID:error类的NSManagedObjectContext方法获取正确的对象,因为

  

与objectWithID:不同,此方法永远不会返回错误。

该方法有效。我能够检索该检索对象的属性。唯一的问题是关系被视为错误。

说这个,我有两个问题。

首先,这是后台线程中fecth NSManagedObject的正确方法吗? 那么,如何在for循环中获取每个获取对象的关系?我是否必须根据通过id获取的特定对象创建NSFetchedRequest来获取关系对象?

提前谢谢。

2 个答案:

答案 0 :(得分:2)

为什么你关心这种关系是错误的?访问它将填补故障并返回数据,您是否因某种原因关注磁盘I / O?

您可以尝试使用预取来减轻一些I / O开销,但它的实用程序仅限于正在获取的实体之间的关系:

https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/CoreDataFramework/Classes/NSFetchRequest_Class/NSFetchRequest.html

在这种情况下,您将使用如下谓词创建一个获取请求:

[NSPredicate predicateWithFormat:@"SELF == %@", objectID];

这将只返回您想要的托管对象,并且通过关系预取关系不会是错误。

您可以通过使用IN子句并一次获取所有对象来进一步优化它:

[NSPredicate predicateWithFormat:@"SELF IN (%@)", desiredObjectIDs];

答案 1 :(得分:0)

您需要确保以下内容:

  • 在传递任何对象ID之前 - 在原始主题上执行[NSManagedObjectContext obtainPermanentIDsForObjects:error:]

(在主线程上)

[managedObjectContext obtainPermanentIDsForObjects:objectIDs error:nil]
  • 在尝试从另一个线程(包括它们的关系)访问这些对象之前,您需要保存原始线程的NSManagedObjectContext。否则,对象将不会存在于持久性中,并且后台线程将无法获取它(或其他关系)。最简单的方法是确保在NSOperation执行开始时调用主线程上的阻塞保存。例如:

dispatch_sync(dispatch_get_main_queue(), { [managedObjectContext save:nil]; });

您可以根据哪种方式更方便地制作NSFetchRequest或直接访问关系;可能直接访问关系。在日常工作结束时,您无需致电[NSManagedObjectContext reset]