Estou trabalhando em um método para sincronizar os dados principais armazenados em um aplicativo do iPhone entre vários dispositivos, como um iPad ou um Mac. Não há muitas estruturas de sincronização (se houver alguma) para uso com o Core Data no iOS. No entanto, tenho pensado no seguinte conceito:
- Uma alteração é feita no armazenamento de dados do núcleo local e a alteração é salva. (a) Se o dispositivo estiver online, ele tenta enviar o conjunto de alterações para o servidor, incluindo o ID do dispositivo que enviou o conjunto de alterações. (b) Se o conjunto de alterações não chegar ao servidor ou se o dispositivo não estiver online, o aplicativo adicionará o conjunto de alterações a uma fila para enviar quando ficar online.
- O servidor, sentado na nuvem, mescla os conjuntos de alterações específicos que recebe com seu banco de dados mestre.
- Depois que um conjunto de alterações (ou uma fila de conjuntos de alterações) é mesclado no servidor em nuvem, o servidor envia todos esses conjuntos de alterações para os outros dispositivos registrados no servidor usando algum tipo de sistema de pesquisa. (Pensei em usar os serviços Push da Apple, mas aparentemente de acordo com os comentários, este não é um sistema viável.)
Existe algo extravagante em que eu preciso estar pensando? Examinei estruturas REST como ObjectiveResource , Core Resource e RestfulCoreData . Claro, todos eles estão trabalhando com o Ruby on Rails, ao qual não estou vinculado, mas é um ponto de partida. Os principais requisitos que tenho para minha solução são:
- Quaisquer alterações devem ser enviadas em segundo plano sem pausar o thread principal.
- Deve usar a menor largura de banda possível.
Eu pensei em vários dos desafios:
- Certifique-se de que os IDs do objeto para os diferentes armazenamentos de dados em diferentes dispositivos estejam conectados ao servidor. Ou seja, terei uma tabela de IDs de objeto e IDs de dispositivo, que são vinculados por meio de uma referência ao objeto armazenado no banco de dados. Terei um registro (DatabaseId [exclusivo para esta tabela], ObjectId [exclusivo para o item no banco de dados inteiro], Datafield1, Datafield2), o campo ObjectId fará referência a outra tabela, AllObjects: (ObjectId, DeviceId, DeviceObjectId). Em seguida, quando o dispositivo envia um conjunto de alterações, ele passa o ID do dispositivo e o objectId do objeto de dados do núcleo no armazenamento de dados local. Em seguida, meu servidor de nuvem verificará o objectId e o ID do dispositivo na tabela AllObjects e encontrará o registro a ser alterado na tabela inicial.
- Todas as alterações devem ter registro de data e hora, para que possam ser mescladas.
- O dispositivo precisará pesquisar o servidor, sem consumir muita bateria.
- Os dispositivos locais também precisarão atualizar qualquer coisa mantida na memória se / quando as alterações forem recebidas do servidor.
Há mais alguma coisa que estou perdendo aqui? Que tipos de estruturas devo examinar para tornar isso possível?
Respostas:
Sugiro ler e implementar cuidadosamente a estratégia de sincronização discutida por Dan Grover na conferência do iPhone 2009, disponível aqui como um documento em pdf.
Essa é uma solução viável e não é tão difícil de implementar (Dan implementou isso em várias de suas aplicações), sobrepondo-se à solução descrita por Chris. Para uma discussão teórica aprofundada sobre sincronização, consulte o artigo de Russ Cox (MIT) e William Josephson (Princeton):
Sincronização de arquivos com pares de horário de vetor
que se aplica igualmente bem aos dados principais com algumas modificações óbvias. Isso fornece uma estratégia geral de sincronização muito mais robusta e confiável, mas requer mais esforço para ser implementada corretamente.
EDITAR:
Parece que o arquivo pdf do Grover não está mais disponível (link quebrado, março de 2015). ATUALIZAÇÃO: o link está disponível através do Way Back Machine aqui
A estrutura do Objective-C chamada ZSync e desenvolvida por Marcus Zarra foi preterida, uma vez que o iCloud finalmente parece suportar a sincronização correta dos dados principais.
fonte
Eu fiz algo semelhante ao que você está tentando fazer. Deixe-me contar o que aprendi e como fiz.
Suponho que você tenha um relacionamento individual entre o objeto Core Data e o modelo (ou esquema db) no servidor. Você simplesmente deseja manter o conteúdo do servidor sincronizado com os clientes, mas os clientes também podem modificar e adicionar dados. Se eu entendi direito, continue lendo.
Adicionei quatro campos para ajudar na sincronização:
No cliente, adicione o código para definir sync_status como 1 no objeto do modelo sempre que algo mudar e precisar ser sincronizado com o servidor. Novos objetos de modelo devem gerar um GUID.
A sincronização é uma única solicitação. A solicitação contém:
O servidor obtém a solicitação e faz isso:
O aplicativo recebe a resposta e faz isso:
Espero que ajude. Usei a palavra registro e modelo de forma intercambiável, mas acho que você entendeu. Boa sorte.
fonte
MAX(last_modified)
, mas isso seria redundante, poisMAX(last_modified)
basta. Osync_status
tem outro papel. Como escrevi anteriormente,MAX(last_modified)
determina o que precisa ser sincronizado com o servidor, enquantosync_status
determina o que precisa ser sincronizado com o servidor.Se você ainda está procurando um caminho a percorrer, procure no Couchbase mobile. Isso basicamente faz tudo o que você deseja. ( http://www.couchbase.com/nosql-databases/couchbase-mobile )
fonte
Semelhante ao @Cris, implementei a classe para sincronização entre cliente e servidor e resolvi todos os problemas conhecidos até agora (enviar / receber dados para / do servidor, mesclar conflitos com base em carimbos de data / hora, remover entradas duplicadas em condições de rede não confiáveis, sincronizar dados aninhados e arquivos etc.)
Você acabou de dizer à classe qual entidade e quais colunas devem ser sincronizadas e onde está seu servidor.
Você pode encontrar fonte, exemplo prático e mais instruções aqui: github.com/knagode/M3Synchronization .
fonte
Aviso ao usuário para atualizar dados via notificação por push. Use um encadeamento em segundo plano no aplicativo para verificar os dados locais e os dados no servidor em nuvem, enquanto as alterações acontecem no servidor, altere os dados locais, vice-versa.
Então, acho que a parte mais difícil é estimar os dados em que lado é inválido.
Espero que isso possa ajudá-lo
fonte
Acabei de publicar a primeira versão da minha nova API de sincronização do Core Data Cloud, conhecida como SynCloud. O SynCloud tem muitas diferenças com o iCloud, pois permite a interface de sincronização para vários usuários. Também é diferente de outras APIs de sincronização porque permite dados relacionais de várias tabelas.
Saiba mais em http://www.syncloudapi.com
Construído com o iOS 6 SDK, está muito atualizado a partir de 27/09/2012.
fonte
Eu acho que uma boa solução para a questão da GUID é "sistema de identificação distribuída". Não sei ao certo qual é o termo correto, mas acho que é o que os documentos do MS SQL Server costumavam chamá-lo (o SQL usa / usou esse método para bancos de dados distribuídos / sincronizados). É bem simples:
O servidor atribui todos os IDs. Cada vez que uma sincronização é feita, a primeira coisa que é verificada é "Quantos IDs me restam neste cliente?" Se o cliente estiver com pouca carga, ele solicitará ao servidor um novo bloco de IDs. O cliente usa IDs nesse intervalo para novos registros. Isso funciona muito bem para a maioria das necessidades, se você pode atribuir um bloco grande o suficiente para "nunca" acabar antes da próxima sincronização, mas não tão grande que o servidor acabe com o tempo. Se o cliente acabar, o tratamento pode ser bem simples, basta dizer ao usuário "desculpe, você não pode adicionar mais itens até sincronizar" ... se eles estiverem adicionando muitos itens, eles não devem sincronizar para evitar dados antigos problemas de qualquer maneira?
Eu acho que isso é superior ao uso de GUIDs aleatórios, porque os GUIDs aleatórios não são 100% seguros e geralmente precisam ser muito mais longos que um ID padrão (128 bits vs 32 bits). Você geralmente possui índices por ID e geralmente mantém os números de ID na memória, portanto, é importante mantê-los pequenos.
Realmente não queria postar como resposta, mas não sei se alguém iria ver como um comentário, e acho importante para esse tópico e não incluído em outras respostas.
fonte
Primeiro, você deve repensar quantos dados, tabelas e relações você terá. Na minha solução, implementei a sincronização através dos arquivos do Dropbox. Observo mudanças no MOC principal e salvo esses dados em arquivos (cada linha é salva como json compactado em gzip). Se houver uma conexão à Internet funcionando, verifico se há alguma alteração no Dropbox (o Dropbox me fornece alterações delta), faço o download e a mesclagem (últimas vitórias) e, finalmente, coloco os arquivos alterados. Antes da sincronização, coloquei o arquivo de bloqueio no Dropbox para impedir que outros clientes sincronizassem dados incompletos. Ao baixar as alterações, é seguro que apenas os dados parciais sejam baixados (por exemplo, perda de conexão com a Internet). Quando o download é concluído (total ou parcial), ele começa a carregar arquivos no Core Data. Quando há relações não resolvidas (nem todos os arquivos são baixados), ele para de carregar os arquivos e tenta concluir o download posteriormente. As relações são armazenadas apenas como GUID, para que eu possa verificar facilmente quais arquivos carregar para ter integridade total dos dados. A sincronização é iniciada após alterações nos dados principais. Se não houver alterações, ele verifica alterações no Dropbox a cada poucos minutos e na inicialização do aplicativo. Além disso, quando as alterações são enviadas ao servidor, envio uma transmissão para outros dispositivos para informá-los sobre as alterações, para que eles possam sincronizar mais rapidamente. Cada entidade sincronizada possui a propriedade GUID (guid também é usado como um nome de arquivo para arquivos de troca). Também tenho banco de dados de sincronização, onde armazeno a revisão do Dropbox de cada arquivo (posso compará-lo quando o delta do Dropbox redefine seu estado). Os arquivos também contêm nome da entidade, estado (excluído / não excluído), guid (igual ao nome do arquivo), revisão do banco de dados (para detectar migrações de dados ou evitar sincronização com versões nunca de aplicativos) e, é claro, os dados (se a linha não for excluída). para que eu possa verificar facilmente quais arquivos carregar para ter total integridade dos dados. A sincronização é iniciada após alterações nos dados principais. Se não houver alterações, ele verifica alterações no Dropbox a cada poucos minutos e na inicialização do aplicativo. Além disso, quando as alterações são enviadas ao servidor, envio uma transmissão para outros dispositivos para informá-los sobre as alterações, para que eles possam sincronizar mais rapidamente. Cada entidade sincronizada possui a propriedade GUID (guid também é usado como um nome de arquivo para arquivos de troca). Também tenho banco de dados de sincronização, onde armazeno a revisão do Dropbox de cada arquivo (posso compará-lo quando o delta do Dropbox redefine seu estado). Os arquivos também contêm nome da entidade, estado (excluído / não excluído), guid (igual ao nome do arquivo), revisão do banco de dados (para detectar migrações de dados ou evitar sincronização com versões nunca de aplicativos) e, é claro, os dados (se a linha não for excluída). para que eu possa verificar facilmente quais arquivos carregar para ter total integridade dos dados. A sincronização é iniciada após alterações nos dados principais. Se não houver alterações, ele verifica alterações no Dropbox a cada poucos minutos e na inicialização do aplicativo. Além disso, quando as alterações são enviadas ao servidor, envio uma transmissão para outros dispositivos para informá-los sobre as alterações, para que eles possam sincronizar mais rapidamente. Cada entidade sincronizada possui a propriedade GUID (guid também é usado como um nome de arquivo para arquivos de troca). Também tenho banco de dados de sincronização, onde armazeno a revisão do Dropbox de cada arquivo (posso compará-lo quando o delta do Dropbox redefine seu estado). Os arquivos também contêm nome da entidade, estado (excluído / não excluído), guid (igual ao nome do arquivo), revisão do banco de dados (para detectar migrações de dados ou evitar sincronização com versões nunca de aplicativos) e, é claro, os dados (se a linha não for excluída).
Esta solução está funcionando para milhares de arquivos e cerca de 30 entidades. Em vez do Dropbox, eu poderia usar o armazenamento de chave / valor como serviço da Web REST, o que eu quero fazer mais tarde, mas não tenho tempo para isso :) Por enquanto, na minha opinião, minha solução é mais confiável que o iCloud e, o que é muito importante, Eu tenho controle total sobre como está funcionando (principalmente porque é meu próprio código).
Outra solução é salvar as alterações do MOC como transações - haverá muito menos arquivos trocados com o servidor, mas é mais difícil fazer o carregamento inicial na ordem correta em dados principais vazios. O iCloud está funcionando dessa maneira e outras soluções de sincronização têm abordagem semelhante, por exemplo, TICoreDataSync .
- ATUALIZAÇÃO
Depois de um tempo, migrei para o Ensembles - recomendo esta solução para reinventar a roda.
fonte