1

我有一个应用程序,它从网络中提取数据,解析它们,并在搜索界面中编译结果。由于数据不是相互依赖的,因此多线程应用程序以同时执行多个获取和解析是有意义的。我在为执行此功能而编写的搜索和解析对象上使用 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 的处理方法是否完全不合时宜?

提前致谢!

4

1 回答 1

1

我认为您的方法没有任何问题,并且以前NSConnection以类似的方式使用过。我唯一看到的是我只是使用NSPort而不是NSMachPort显式使用。

或者,有没有更简单的方法来构建线程间异步通信?

我不认为 Apple 正在推广用于线程间通信的分布式对象。IIRC 这个猜测主要基于我所看到的文档,这些文档确实促进了线程间通信的 DO,但此后已被删除或编辑。

我还认为 NSObject 上与线程相关的 performSelector: 方法更容易使用:

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait

(而第二个仅从 10.5 开始可用)。

于 2009-12-11T13:33:41.673 回答