Проблем със синхронни разпределени обекти през NSConnection

Имам приложение, което извлича данни от мрежата, анализира ги и компилира резултатите в интерфейс за търсене. Тъй като данните не са взаимно зависими, има смисъл приложението да бъде многонишково, за да изпълнява едновременно множество извличания и анализи. Използвам 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];
 }
}

Приложението разчита на основни данни, които съм събрал, че най-вече не са безопасни за нишки. Имам различен NSManagedObjectContext за всяка операция за търсене/анализ (и един за контролера) и предавам само NSManagedObjectId между операции или прокси обекти.

Операциите съобщават завършените резултати от анализ обратно на своя контролер чрез обект NSConnection. Контролерът конструира NSConnection с помощта на обект NSMachPort, задава се като основен обект и дава същия обект 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 за обща комуникация между нишки, дадена тук.

Трябва да кажа, че през повечето време това работи прекрасно: уведомленията от rootProxy на NSConnection се публикуват в цикъла за изпълнение в главната нишка, както се очаква, и изчакват за приемане, докато обектът на контролера е готов. Въпреки това, в някои от моите тестови случаи това кара основните данни да спират до скърцане, защото понякога съобщенията стигат до обекта на контролера в същата нишка като обекта NSInvocationOperation, който извиква rootProxy обекта.

Поставих точка за отстраняване на грешки в контролера на съобщението, което се изпраща, когато операцията за търсене/анализ е завършена, и разбира се, понякога (само понякога) изпълняваната нишка не е основната. Някой има ли идея защо може да се случи това? Или има по-прост начин за конструиране на асинхронна комуникация между нишки? ИЛИ подходът ми за Core Data е напълно неподходящ?

Благодаря предварително!


person Community    schedule 11.12.2009    source източник


Отговори (1)


Не виждам нищо лошо във вашия подход и съм използвал NSConnection по подобен начин преди. Единственото нещо, което виждам, е, че току-що използвах NSPort вместо изрично да използвам NSMachPort.

Или има по-прост начин за конструиране на асинхронна комуникация между нишки?

Не мисля, че Apple вече насърчава разпределени обекти за комуникация между нишки. Това предположение на IIRC се основава най-вече на документация, която съм виждал спомената, която наистина насърчава DO за комуникация между нишки, но оттогава е премахната или редактирана.

Също така мисля, че свързаните с нишките performSelector: методи на NSObject са много по-лесни за използване:

- (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 нататък).

person Adrian    schedule 11.12.2009
comment
Благодаря ви за отговора. Виждал съм съобщението performSelectorOnMainThread, замесено в документацията по-рано, но се отдръпнах от него поради възприеманото му естество на ниско ниво. Ще опитам това по-късно днес. Освен това (ако работи) опростява дизайна на рамката доста. Тези портове и връзки могат бързо да се объркат! Благодаря отново! - person ; 11.12.2009