Como posso partilhar uma loja Núcleo de dados entre processos usando NSDistributedNotifications?

StackOverflow https://stackoverflow.com/questions/1815518

  •  07-07-2019
  •  | 
  •  

Pergunta

Fundo

Eu já postei uma pergunta sobre os princípios de compartilhando uma loja core Data entre processos .

Eu estou tentando implementar as recomendações dadas e eu estou correndo em problemas.

Meu objetivo

Eu tenho dois processos - o ajudante de aplicativos ea interface do usuário. Ambos compartilham um único repositório de dados. Eu quero a interface do usuário para atualizar a sua NSManagedObjectContext quando o Helper App salvou novos dados para a loja.

Programa atual fluxo

  1. O Processo Helper App escreve dados para a loja.

  2. No auxiliar de App, I ouvir notificações NSManagedObjectContextDidSaveNotification.

  3. Quando o contexto é salvo, eu codificar os objetos inseridos, excluídos e atualizados usando suas representações URI e NSArchiver.

  4. Eu enviar um NSNotification ao NSDistributedNotificationCenter com este dicionário codificado como o userInfo.

  5. O Processo UI está escutando para a economia de notificação. Quando ele recebe a notificação, ele Desarquiva o userInfo usando NSUnarchiver.

  6. Parece-se todos os / inseridas / objetos excluídos atualizados das URIs dadas e os substitui por NSManagedObjects.

  7. Ele constrói uma NSNotification com os objetos atualizados / inseridas / suprimidas.

  8. Eu chamo mergeChangesFromContextDidSaveNotification:. Do contexto Managed Object do Processo de UI, passando o NSNotification I construídos na etapa anterior

O Problema

objetos inseridos são criticado na UI Managed Object Context bem e eles aparecem na interface do usuário. O problema vem com objetos atualizados. Eles simplesmente não fazer atualização.

O que eu tentei

  1. A coisa mais óbvia a tentar faria seja para passar o save Notificação a partir do processo de Helper para a App processo de UI. Fácil, não é? Bem não. Notificações distribuídos não vai permita-me a fazer isso como o userInfo dicionário não está no direito formato. É por isso que eu estou fazendo todo o NSArchiving coisas.

  2. chamado

    Eu tentei refreshObject: mergeChanges: SIM no os NSManagedObjects a ser atualizado, mas isso não parece ter qualquer efeito.

  3. Eu tentei realizar o mergeChangesFromContextDidSaveNotification: selector no segmento principal eo thread atual. Nem parece afectar o resultado.

  4. Eu tentei usar mergeChangesFromContextDidSaveNotification: antes entre as threads, que de Naturalmente é muito mais simples e funcionou perfeitamente. Mas eu preciso esta mesma funcionalidade entre processos.

Alternativas?

Estou faltando alguma coisa aqui? Eu estou constantemente recebendo o sentimento que eu estou fazendo isso muito mais complexo do que ele precisa ser, mas depois de ler a documentação várias vezes e passar alguns dias sólidas sobre isso, eu não consigo ver nenhuma outra maneira de refrescar o MOC de a interface do usuário.

Existe uma maneira mais elegante de fazer isso? Ou estou apenas fazendo um erro bobo algum lugar no meu código?

O Código

Eu tentei torná-lo mais legível possível, mas ainda é uma bagunça. Desculpe.

Helper Código App

   -(void)workerThreadObjectContextDidSave:(NSNotification *)saveNotification {
        NSMutableDictionary *savedObjectsEncodedURIs = [NSMutableDictionary dictionary];
        NSArray *savedObjectKeys = [[saveNotification userInfo] allKeys];

        for(NSString *thisSavedObjectKey in savedObjectKeys) {
            // This is the set of updated/inserted/deleted NSManagedObjects.
            NSSet *thisSavedObjectSet = [[saveNotification userInfo] objectForKey:thisSavedObjectKey];
            NSMutableSet *thisSavedObjectSetEncoded = [NSMutableSet set];

            for(id thisSavedObject in [thisSavedObjectSet allObjects]) {
                // Construct a set of URIs that will be encoded as NSData
                NSURL *thisSavedObjectURI = [[(NSManagedObject *)thisSavedObject objectID] URIRepresentation];
                [thisSavedObjectSetEncoded addObject:thisSavedObjectURI];
            }
            // Archive the set of URIs.
            [savedObjectsEncodedURIs setObject:[NSArchiver archivedDataWithRootObject:thisSavedObjectSetEncoded] forKey:thisSavedObjectKey];
        }

        if ([[savedObjectsEncodedURIs allValues] count] > 0) {
            // Tell UI process there are new objects that need merging into it's MOC
            [[NSDistributedNotificationCenter defaultCenter] postNotificationName:@"com.synapticmishap.lapsus.save" object:@"HelperApp" userInfo:(NSDictionary *)savedObjectsEncodedURIs];
        }
    }

Código UI

-(void)mergeSavesIntoMOC:(NSNotification *)notification {
    NSDictionary        *objectsToRefresh        = [notification userInfo];
    NSMutableDictionary *notificationUserInfo    = [NSMutableDictionary dictionary];
    NSArray *savedObjectKeys = [[notification userInfo] allKeys];

    for(NSString *thisSavedObjectKey in savedObjectKeys) {
        // Iterate through all the URIs in the decoded set. For each URI, get the NSManagedObject and add it to a set.
        NSSet *thisSavedObjectSetDecoded = [NSUnarchiver unarchiveObjectWithData:[[notification userInfo] objectForKey:thisSavedObjectKey]];
        NSMutableSet *savedManagedObjectSet = [NSMutableSet set];

        for(NSURL *thisSavedObjectURI in thisSavedObjectSetDecoded) {
            NSManagedObject *thisSavedManagedObject = [managedObjectContext objectWithID:[persistentStoreCoordinator managedObjectIDForURIRepresentation:thisSavedObjectURI]];
            [savedManagedObjectSet addObject:thisSavedManagedObject];
            // If the object is to be updated, refresh the object and merge in changes.
            // This doesn't work!
            if ([thisSavedObjectKey isEqualToString:NSUpdatedObjectsKey]) {
                [managedObjectContext refreshObject:thisSavedManagedObject mergeChanges:YES];
                [managedObjectContext save:nil];
            }
        }
        [notificationUserInfo setObject:savedManagedObjectSet forKey:thisSavedObjectKey];
    }
    // Build a notification suitable for merging changes into MOC.
    NSNotification *saveNotification = [NSNotification notificationWithName:@"" object:nil userInfo:(NSDictionary *)notificationUserInfo];
    [managedObjectContext performSelectorOnMainThread:@selector(mergeChangesFromContextDidSaveNotification:)
                                    withObject:saveNotification
                                 waitUntilDone:YES];
}
Foi útil?

Solução

Você está procurando - (void) refreshObject:. (NSManagedObject *) mergeChanges objeto: (BOOL) flag Acredito

Isto irá atualizar o objeto com a informação no armazenamento persistente, mesclar as alterações, se quiser.

Outras dicas

Eu usei o método em

http://www.mlsite.net/blog/?p=518

, em seguida, cada objeto é corretamente criticada, mas as faltas são buscar em cache para ainda sem atualização

Eu tive que fazer [Moc stalenessInterval = 0];

E finalmente funcionou, com relação.

Eu iria com a sugestão de Mike e só ver o arquivo de armazenamento para mudanças.

Embora possa não ser o mais eficiente, eu tive sucesso usando - [NSManagedObjectContext reset] de um segundo processo quando há uma mudança a uma loja. No meu caso caso, o código é bastante linear - tudo o que faço é executar uma solicitação de busca para alguns dados depois de reiniciar. Eu não sei como isso vai funcionar com ligações e uma interface complicada, mas você pode ser capaz de postar uma notificação para as coisas de atualização manualmente se não for tratada automaticamente.

Eu tive esse mesmo problema exato com um aplicativo para iPhone que eu tenho vindo a trabalhar. No meu caso, a solução envolveu a criação stalenessInterval do Contexto a algo adequadamente infinitesimal (por exemplo, 0,5 segundos).

Isso funciona, exceto para caixas de areia apps. Não é possível enviar uma notificação com uma informação do usuário dict. Em vez disso considerar alguma outra IPC como XPC ou fazer.

Em uma nota lateral, usando NSDustributedNotificationCenter nem sempre é 100% se o sistema está ocupado.

Configuração stalenessInterval de obras contexto de objeto gerenciado. O meu caso envolve vários segmentos em vez de processo embora.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top