Objetos Distribuídos síncrona NSConnection Issue
-
19-09-2019 - |
Pergunta
Eu tenho um aplicativo que puxa os dados da web, analisa-los, e compila os resultados em uma interface de pesquisa. Uma vez que os dados não são co-dependente, fazia sentido para multi-thread do aplicativo para executar múltiplas buscas e analisa simultaneamente. Eu uso NSInvocationOperation em uma busca e objeto de análise que eu escrevi para executar esta função.
No objeto controlador Eu tenho o seguinte método:
-(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];
}
}
O aplicativo depende Core Data, que eu recolhi é principalmente enfiar inseguro. Eu tenho um NSManagedObjectContext diferente para cada operação de busca / parse (e um para o controlador), e só passar o NSManagedObjectId entre as operações ou objetos de proxy.
As operações de comunicar os resultados de análise concluída ao seu controlador através de um objeto NSConnection. O controlador constrói o NSConnection usando um objeto NSMachPort, define-se como o objeto raiz, e dá o mesmo objeto NSConnection a cada um dos alvos dos NSInvocationOperations. O controlador então enfileira o NSInvocationOperation para execução em seu próprio NSOperationQueue.
Na busca threader objeto Eu tenho o seguinte método:
-(void) executeSearchAndParse
{
id parentServer = [threadConnection rootProxy];
[parentServer setProtocolForProxy:@protocol(SearchParseProtocol)];
NSArray *importResults = [targetSchema generatedDataSetIds];
[parentServer schemaFinished:targetSchema];
[parentServer addSearchResults:importResults];
}
Creio ter seguido o exemplo da Apple de comunicação inter-thread genérico dado aqui .
Eu tenho que dizer que na maioria das vezes, isso funciona muito bem: As notificações do NSConnection rootProxy são lançados no loop de execução na thread principal como esperado e espera para retirada até que o objeto controlador está pronto. No entanto, em alguns dos meus casos de teste que provoca Core Data para moer a uma parada brusca, porque às vezes as mensagens torná-lo para o objeto controlador no mesmo segmento como o objeto NSInvocationOperation que está chamando o objeto rootProxy .
Eu coloquei um ponto depurador no controlador na mensagem que é enviada quando a operação de busca / análise estiver concluída, e com certeza, às vezes (só às vezes) o thread em execução é não o principal. Alguém tem uma idéia de por que isso pode ocorrer? Ou, se existe uma maneira mais simples de construir inter-thread comunicação assíncrona? OR é a minha abordagem para Core Data totalmente fora de forma?
Agradecemos antecipadamente!
Solução
Não vejo mal qualquer coisa com sua abordagem e usaram NSConnection
de maneira semelhante antes. A única coisa que eu vejo é que eu usei apenas NSPort
em vez de usar NSMachPort
explicitamente.
Ou, se existe uma maneira mais simples de construir inter-thread comunicação assíncrona?
Eu não acho que a Apple está promovendo objetos ditributed para a comunicação inter-thread mais. IIRC esta suposição se baseia principalmente em documentação que tenho visto mencionado o que realmente promove DOs para a comunicação inter-thread, mas que desde então têm sido removido ou editado.
Eu também acho que as relacionadas com a rosca performSelector: métodos em NSObject são muito mais fáceis de usar:
- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait
- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait
(enquanto o segundo só está disponível a partir de 10,5 por diante).