2012-08-14 68 views
0

我使用下面的代码来运行分析我的XML文件的功能...iOS:如何在使用Grand Central Dispatch(GCD)时同步我的managedObjectContext?

dispatch_queue_t queue = dispatch_queue_create("updateQueue", DISPATCH_QUEUE_CONCURRENT); 

dispatch_async(queue,^ { [self updateFromXMLFile:@"http://path/to/file.xml"]; }); 
dispatch_async(queue,^ { [self updateFromXMLFile:@"http://path/to/file1.xml"]; }); 
dispatch_async(queue,^ { [self updateFromXMLFile:@"http://path/to/file2.xml"]; }); 
dispatch_async(queue,^ { [self updateFromXMLFile:@"http://path/to/file3.xml"]; }); 

dispatch_barrier_async(queue,^ { 
    dispatch_async(dispatch_get_main_queue(),^ { 
      [self setBottomBarToUpdated]; 
    }); 
}); 

这里下面是功能updateFromXMLFile

- (BOOL) updateFromXMLFile:(NSString *)pathToFile { 

     NSURL *url = [[NSURL alloc] initWithString:pathToFile]; 
     NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithContentsOfURL:url]; 

     XMLParser *parser = [[XMLParser alloc] initXMLParser]; 

     parser.managedObjectContext = self.managedObjectContext; 

     [xmlParser setDelegate: parser]; 

     BOOL success = [xmlParser parse]; 

     if(success) 
       return TRUE; 
     else 
       return FALSE; 

} 

我来跨越的问题是此错误消息:***Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSCFSet: 0xc675e10> was mutated while being enumerated.'

我猜测它与所有进程搞乱我的ManagedObjectContext在同一时间。我不知道如何处理,但。有任何想法吗?谢谢!

+0

强烈建议检讨核心数据的WWDC 2012会议上,他们涵盖了所有该线程的东西 – CSmith 2012-08-14 15:46:37

+0

你尝试注释四派遣一个呼叫来查看其中是否特别是创造了什么问题?我会从那里开始。另外,有没有一种方法可以序列化解析?你有没有想过NSOperationQueue? – Ravi 2012-08-14 15:58:31

回答

1

您需要显示XMLParser如何处理其委托职责的代码,因为这就是所谓的。

现在,您可以在单独的线程中同时解析多个文件。它们都调用了不同的XMLParser对象,但每个对象都使用相同的受管对象上下文(MOC)。

如果您正在使用默认的MOC设置,则需要将所有MOC调用重新发送到主线程(如果是,实际上是您首次创建上下文的位置)。如果你使用限制,并且你的MOC没有在主线程中创建,那么你给自己更多的麻烦。

但是,这是一个非常简单的修复。在该解析器委托方法中,无论何时使用托管对象上下文,都要将其放在调用中以在主线程上分派该部分。

dispatch_async(dispatch_get_main_queue(), ^{ 
    // Put your code that accesses the MOC in here. 
}); 

现在,对于批量下载到核心数据中,您最好使用两种方法之一。

创建一个新的MOC,直接连接到持久存储协调,做你的储蓄在那里。您的主要MOC需要观察保存通知并合并这些更改。

或者,使新的MOC是你的主要MOC的孩子,并直接保存到它,那么它可以节省。

但是,如果你的管理对象上下文或者是NSMainQueueConcurrencyType或NSPrivateQueueConcurrency型(仅做上述第二种选择方式),那么你可以使用它的方法perfromBlock ...

[managedObjectContext performBlock:^{ 
    // Do your MOC stuff in here 
}]; 

底线可以使用三种并发类型之一来创建MOC。如果它是NSConfinementConcurrencyType,那么你不能在它创建的线程之外触摸它。如果它是NSMainQueueConcurrencyType,则必须使用performBlock *或仅在主线程中触摸它。如果它是NSPrivateConcurrencyType,则必须使用performBlock *。

+0

解析文件太大了,我想这里就放在这里。我需要把它清理干净;/- 但是,我ManagedObjectContext的类型是NSManagedObjectContext'的'我有4个不同NSManagedObject'的'子类我解析每个对象类型。我想我访问MOC的唯一地方是在@synthesize,[的appDelegate saveContext]要求四个对象类型一次IM关闭XML文件的库元素,而我认为这是它。我尝试了你的第一个建议,但似乎没有工作仍然有错误;/ – daveomcd 2012-08-14 19:07:23

+0

你不能以任何你喜欢的方式访问一个托管对象的上下文。核心数据有非常严格的规则,必须遵守。任何时候你用MOC(包括它包含的管理对象)做任何事情都必须遵守规则。我在他提供的答案中总结了他们。 – 2012-08-14 19:27:17

1

问题是你不能使用并发队列接口到MOC,你必须使用串行接口。将您的队列创建更改为

dispatch_queue_t queue = dispatch_queue_create("updateQueue", DISPATCH_QUEUE_SERIAL); 

一切都会好的。再次,这样做的原因是最终的XMLParser对象正在同时尝试与moc进行交互。

你的选择是由XMLParser(或任何类)做什么决定的。如果一个课程在与MOC交互之前做了繁重的工作,或者它从网上下载数据,那么你会通过并发获得一些东西。

我建议你做的是从URLS下载你需要的数据,然后连续与MOC一起工作。你必须在单线程(在iOS中)与MOC交互,但不一定是mainThread - 只要它是唯一的线程就可以是任何线程。这意味着如果您创建自己的串行队列,则必须在该队列上完成所有操作,包括创建MOC!

回到您的代码。让我们假设你在mainQueue上做所有的核心数据(现在)。解决方法是将您的代码更改为:

dispatch_async(dispatch_get_global_queue(0,0) { 
    NSURL *url = [[NSURL alloc] initWithString:pathToFile]; 
    NSData *data = [NSData dataWithContentsOfURL:url]; 
    NSXMLParser *xmlParser = [[NSXMLParser alloc] initWithData:data]; 
    XMLParser *parser = [[XMLParser alloc] initXMLParser]; 
    parser.managedObjectContext = self.managedObjectContext; 
    [xmlParser setDelegate: parser]; 

    dispatch_async(dispatch_get_main_queue(), { 
     BOOL success = [xmlParser parse]; 

     // need some means to associate success/failure with the URL 
    }); 

您尽可能多地在打MOC时进行序列化。对MOC使用串行队列的唯一区别是,您将消息队列而不是mainQueue。

+1

我不知道我看到并发队列的问题。这些文件使用完全独立的对象进行处理。唯一的问题是与MOC,即使串行队列,这也是一个问题,因为任何时候从多线程访问MOC都是一个问题。 – 2012-08-14 16:18:00

+0

我在我的代码所做的是为使用并行操作来处理数据,然后获得了商务部已于串行队列完成。关键是你的错误是由于moc的并发访问。这也得到了所有moc工作在它自己的线程中(因为串行队列不在主线程中)。 – 2012-08-14 17:33:00

+0

无论如何,你可以更新你的答案来描述你在最新的评论中说的话。不知道我遵循...你不使用块的个别方法调用? – daveomcd 2012-08-14 19:08:59

相关问题