我有一个应用程序,它从网络中提取数据,解析它们,并在搜索界面中编译结果。由于数据不是相互依赖的,因此多线程应用程序以同时执行多个获取和解析是有意义的。我在为执行此功能而编写的搜索和解析对象上使用 NSInvocationOperation。
在控制器对象中,我有以下方法:
-(void) searchAndParseAsynchronously {
NSPort *serverPort = [NSMachPort port];
NSConnection *serverConnection = [NSConnection connectionWithReceivePort:serverPort sendPort:serverPort];
[serverConnection setRootObject:self];
for (NSURL *urlToProcess in self.urlsToFetch)
{
BaseSearchParser *searcherForURL = [BaseSearchParser newSearchParserWithParameters:self.searchParams];
searcherForURL.urlToDocument = urlToDocument;
SearchThreader *searchThreader = [SearchThreader new];
searchThreader.threadConnection = comConnection;
searchThreader.targetSchema = searcherForURL;
NSInvocationOperation *threaderOperation = [[NSInvocationOperation alloc] initWithTarget:searchThreader
selector:@selector(executeSearchParse)
object:nil];
[self.operationQueue addOperation:threaderOperation];
}
}
该应用程序依赖于 Core Data,我收集到的这些数据大多是线程不安全的。我为每个搜索/解析操作(和一个控制器)有一个不同的 NSManagedObjectContext,并且只在操作或代理对象之间传递 NSManagedObjectId。
这些操作通过 NSConnection 对象将完成的解析结果传送回它们的控制器。控制器使用 NSMachPort 对象构造 NSConnection,将自己设置为根对象,并将相同的 NSConnection 对象提供给 NSInvocationOperations 的每个目标。然后控制器将 NSInvocationOperation 排入队列以在其自己的 NSOperationQueue 中执行。
在搜索线程对象中,我有以下方法:
-(void) executeSearchAndParse
{
id parentServer = [threadConnection rootProxy];
[parentServer setProtocolForProxy:@protocol(SearchParseProtocol)];
NSArray *importResults = [targetSchema generatedDataSetIds];
[parentServer schemaFinished:targetSchema];
[parentServer addSearchResults:importResults];
}
我相信我已经遵循了此处给出的通用线程间通信的 Apple 示例。
我不得不说,在大多数情况下,这很好用:来自 NSConnection rootProxy 的通知按预期发布到主线程中的运行循环,并等待拾取,直到控制器对象准备好。然而,在我的一些测试用例中,它会导致 Core Data 停止工作,因为有时消息会在与调用 rootProxy 对象的 NSInvocationOperation 对象相同的线程中到达控制器对象。
我在控制器中放置了一个调试器点,该点位于搜索/解析操作完成时发送的消息上,果然,有时(只是有时)执行线程不是主要线程。有谁知道为什么会发生这种情况?或者,有没有更简单的方法来构建线程间异步通信?或者我对 Core Data 的处理方法是否完全不合时宜?
提前致谢!