【发布时间】:2009-12-11 12:14:09
【问题描述】:
我有一个应用程序,它从网络中提取数据、解析它们,然后在搜索界面中编译结果。由于数据不是相互依赖的,因此多线程应用程序以同时执行多个获取和解析是有意义的。我在为执行此功能而编写的搜索和解析对象上使用 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 给出的通用线程间通信示例here。
我不得不说,在大多数情况下,这很有效:来自 NSConnection rootProxy 的通知按预期发布到主线程中的运行循环,并等待获取,直到控制器对象准备好。然而,在我的一些测试用例中,它会导致 Core Data 停止工作,因为有时消息会在与调用 rootProxy 对象的 NSInvocationOperation 对象相同的线程中发送到控制器对象。
我在控制器中放置了一个调试器点,当搜索/解析操作完成时发送的消息上,果然,有时(只是有时)执行线程是不是主要的。有谁知道为什么会发生这种情况?或者,有没有更简单的方法来构建线程间异步通信?或者我的 Core Data 方法是否完全不合时宜?
提前致谢!
【问题讨论】:
标签: objective-c cocoa multithreading core-data distributed-objects