Pracowałem nad metodą synchronizacji podstawowych danych przechowywanych w aplikacji iPhone'a między wieloma urządzeniami, takimi jak iPad lub Mac. Nie ma wielu (jeśli w ogóle) ram synchronizacji do użycia z Core Data na iOS. Zastanawiałem się jednak nad następującą koncepcją:
- Dokonano zmiany w lokalnym podstawowym magazynie danych, a zmiana została zapisana. (a) Jeśli urządzenie jest w trybie online, próbuje wysłać zestaw zmian na serwer, w tym identyfikator urządzenia, które wysłało zestaw zmian. (b) Jeśli zestaw zmian nie dotrze do serwera lub urządzenie nie jest w trybie online, aplikacja doda zestaw zmian do kolejki do wysłania, gdy przejdzie w tryb online.
- Serwer siedzący w chmurze łączy określone zestawy zmian, które otrzymuje, ze swoją główną bazą danych.
- Po scaleniu zestawu zmian (lub kolejki zestawów zmian) na serwerze w chmurze serwer wypycha wszystkie te zestawy zmian na inne urządzenia zarejestrowane na serwerze za pomocą pewnego rodzaju systemu odpytywania. (Myślałem o skorzystaniu z usług Push Apple, ale najwyraźniej według komentarzy nie jest to realny system).
Czy jest coś wymyślonego, o czym muszę pomyśleć? Patrzyłem na frameworki REST, takie jak ObjectiveResource , Core Resource i RestfulCoreData . Oczywiście wszystkie one współpracują z Ruby on Rails, z którymi nie jestem związany, ale jest to miejsce na początek. Główne wymagania, jakie mam dla mojego rozwiązania, to:
- Wszelkie zmiany należy przesyłać w tle bez wstrzymywania głównego wątku.
- Powinien wykorzystywać możliwie najmniejszą przepustowość.
Myślałem o wielu wyzwaniach:
- Upewnij się, że identyfikatory obiektów dla różnych magazynów danych na różnych urządzeniach są dołączone na serwerze. To znaczy, będę mieć tabelę identyfikatorów obiektów i identyfikatorów urządzeń, które są powiązane poprzez odwołanie do obiektu przechowywanego w bazie danych. Będę miał rekord (DatabaseId [unikalny dla tej tabeli], ObjectId [unikalny dla elementu w całej bazie danych], Datafield1, Datafield2), pole ObjectId będzie odnosić się do innej tabeli, AllObjects: (ObjectId, DeviceId, DeviceObjectId). Następnie, gdy urządzenie wypchnie zestaw zmian, przekaże identyfikator urządzenia i identyfikator obiektu z podstawowego obiektu danych w lokalnym magazynie danych. Następnie mój serwer w chmurze sprawdzi obiekt ID i identyfikator urządzenia w tabeli AllObjects i znajdzie rekord do zmiany w tabeli początkowej.
- Wszystkie zmiany powinny być oznaczone datą, aby można je było scalić.
- Urządzenie będzie musiało sondować serwer bez zużywania zbyt dużej baterii.
- Lokalne urządzenia będą również musiały aktualizować wszystko, co jest w pamięci, jeśli / kiedy zmiany zostaną otrzymane z serwera.
Czy brakuje mi czegoś jeszcze? Na jakie ramy powinienem spojrzeć, aby było to możliwe?
Odpowiedzi:
Proponuję uważnie przeczytać i wdrożyć strategię synchronizacji omówioną przez Dana Grovera na konferencji iPhone 2009, dostępną tutaj jako dokument pdf.
Jest to realne rozwiązanie i nie jest trudne do wdrożenia (Dan zaimplementował to w kilku swoich aplikacjach), pokrywając się z rozwiązaniem opisanym przez Chrisa. Szczegółową, teoretyczną dyskusję na temat synchronizacji można znaleźć w artykule Russa Coxa (MIT) i Williama Josephsona (Princeton):
Synchronizacja plików z parami czasu wektora
co dotyczy równie dobrze podstawowych danych z pewnymi oczywistymi modyfikacjami. Zapewnia to ogólnie o wiele bardziej niezawodną i niezawodną strategię synchronizacji, ale wymaga więcej wysiłku, aby zostać poprawnie wdrożonym.
EDYTOWAĆ:
Wygląda na to, że plik pdf Grovera nie jest już dostępny (uszkodzony link, marzec 2015). UPDATE: link jest dostępny poprzez drogę powrotną Maszynie tutaj
Framework Objective-C o nazwie ZSync i opracowany przez Marcusa Zarrę został przestarzały, biorąc pod uwagę, że iCloud wydaje się wreszcie wspierać prawidłową synchronizację podstawowych danych.
źródło
Zrobiłem coś podobnego do tego, co próbujesz zrobić. Pozwól, że powiem ci, czego się nauczyłem i jak to zrobiłem.
Zakładam, że istnieje relacja jeden-do-jednego między obiektem Core Data a modelem (lub schematem db) na serwerze. Chcesz po prostu zsynchronizować zawartość serwera z klientami, ale klienci mogą również modyfikować i dodawać dane. Jeśli dobrze to zrozumiałem, czytaj dalej.
Dodałem cztery pola, aby pomóc w synchronizacji:
Na kliencie dodaj kod, aby ustawić sync_status na 1 w obiekcie modelu, ilekroć coś się zmieni i trzeba zsynchronizować z serwerem. Nowe obiekty modelu muszą generować identyfikator GUID.
Synchronizacja jest pojedynczym żądaniem. Wniosek zawiera:
Serwer otrzymuje żądanie i wykonuje następujące czynności:
Aplikacja odbiera odpowiedź i wykonuje następujące czynności:
Mam nadzieję że to pomogło. Użyłem zapisu słowa i modelu zamiennie, ale myślę, że masz pomysł. Powodzenia.
źródło
MAX(last_modified)
, ale byłoby to zbędne, ponieważMAX(last_modified)
wystarczy.sync_status
Ma inną rolę. Jak napisałem wcześniej,MAX(last_modified)
określa, co należy zsynchronizować z serwerem, async_status
określa, co należy zsynchronizować z serwerem.Jeśli nadal szukasz drogi, zajrzyj do telefonu komórkowego Couchbase. To właściwie wszystko, czego chcesz. ( http://www.couchbase.com/nosql-databases/couchbase-mobile )
źródło
Podobnie jak @Cris zaimplementowałem klasę do synchronizacji między klientem a serwerem i rozwiązałem dotychczas wszystkie znane problemy (wysyłanie / odbieranie danych do / z serwera, scalanie konfliktów na podstawie znaczników czasu, usuwanie duplikatów wpisów w niepewnych warunkach sieciowych, synchronizowanie zagnieżdżonych danych i pliki itp.)
Po prostu powiedz klasie, która jednostka i które kolumny powinna zsynchronizować oraz gdzie jest twój serwer.
Możesz znaleźć źródło, działający przykład i więcej instrukcji tutaj: github.com/knagode/M3Synchronization .
źródło
Powiadom użytkownika o konieczności aktualizacji danych za pomocą powiadomienia push. Użyj wątku w tle w aplikacji, aby sprawdzić dane lokalne i dane na serwerze w chmurze, podczas gdy zmiana dzieje się na serwerze, zmień dane lokalne i odwrotnie.
Myślę więc, że najtrudniejszą częścią jest oszacowanie danych, w których strona jest nieważna.
Mam nadzieję, że to może ci pomóc
źródło
Właśnie opublikowałem pierwszą wersję mojego nowego API Core Data Cloud Syncing, znanego jako SynCloud. SynCloud ma wiele różnic w stosunku do iCloud, ponieważ pozwala na interfejs synchronizacji dla wielu użytkowników. Różni się także od innych interfejsów API, ponieważ pozwala na tworzenie relacyjnych danych z wieloma tabelami.
Dowiedz się więcej na http://www.syncloudapi.com
Kompilacja z iOS 6 SDK, jest bardzo aktualna od 27.09.2012.
źródło
Myślę, że dobrym rozwiązaniem problemu z identyfikatorem GUID jest „rozproszony system identyfikacji”. Nie jestem pewien, jaki jest prawidłowy termin, ale myślę, że tak nazywali go dokumenty MS SQL Server (SQL używa / używał tej metody w rozproszonych / synchronizowanych bazach danych). To całkiem proste:
Serwer przypisuje wszystkie identyfikatory. Za każdym razem, gdy synchronizacja jest wykonywana, pierwszą rzeczą, która jest sprawdzana, jest „Ile identyfikatorów pozostałem na tym kliencie?” Jeśli kończy się klient, prosi serwer o nowy blok identyfikatorów. Następnie klient używa identyfikatorów w tym zakresie do nowych rekordów. Działa to doskonale w przypadku większości potrzeb, jeśli można przypisać blok wystarczająco duży, aby „nigdy” nie kończył się przed następną synchronizacją, ale nie tak duży, aby z czasem skończył się serwer. Jeśli klient kiedykolwiek się skończy, obsługa może być dość prosta, po prostu powiedz użytkownikowi „przepraszam, że nie możesz dodać więcej elementów, dopóki nie zsynchronizujesz” ... jeśli dodają tyle elementów, czy nie powinny synchronizować, aby uniknąć nieaktualnych danych w każdym razie problemy?
Myślę, że jest to lepsze niż używanie losowych identyfikatorów GUID, ponieważ losowe identyfikatory GUID nie są w 100% bezpieczne i zwykle muszą być znacznie dłuższe niż standardowy identyfikator (128-bitowy vs 32-bitowy). Zazwyczaj masz indeksy według ID i często przechowujesz numery ID w pamięci, dlatego ważne jest, aby były małe.
Naprawdę nie chciałem publikować jako odpowiedzi, ale nie wiem, czy ktokolwiek widziałby to jako komentarz i myślę, że jest to ważne dla tego tematu i nieujęte w innych odpowiedziach.
źródło
Najpierw zastanów się, ile danych, tabel i relacji będziesz mieć. W moim rozwiązaniu zaimplementowałem synchronizację poprzez pliki Dropbox. Obserwuję zmiany w głównym MOC i zapisuję te dane w plikach (każdy wiersz zapisywany jest jako gzipped json). Jeśli działa połączenie internetowe, sprawdzam, czy są jakieś zmiany w Dropbox (Dropbox daje mi zmiany delta), pobieram je i łączę (ostatnie zwycięstwa), a na koniec umieszczam zmienione pliki. Przed synchronizacją umieszczam plik blokady na Dropbox, aby uniemożliwić innym klientom synchronizację niekompletnych danych. Podczas pobierania zmian można bezpiecznie pobierać tylko częściowe dane (np. Utracone połączenie internetowe). Po zakończeniu pobierania (całkowicie lub częściowo) zaczyna się ładowanie plików do podstawowych danych. Gdy istnieją nierozwiązane relacje (nie wszystkie pliki są pobierane), zatrzymuje ładowanie plików i próbuje zakończyć pobieranie później. Relacje są przechowywane tylko jako GUID, dzięki czemu mogę łatwo sprawdzić, które pliki należy załadować, aby mieć pełną integralność danych. Synchronizacja rozpoczyna się po wprowadzeniu zmian w podstawowych danych. Jeśli nie ma żadnych zmian, sprawdza zmiany w Dropbox co kilka minut i podczas uruchamiania aplikacji. Dodatkowo, gdy zmiany są wysyłane na serwer, wysyłam transmisję do innych urządzeń, aby poinformować ich o zmianach, aby mogli szybciej synchronizować. Każda zsynchronizowana jednostka ma właściwość GUID (identyfikator GUID służy również jako nazwa pliku dla plików wymiany). Mam również bazę danych Sync, w której przechowuję wersję Dropbox każdego pliku (mogę to porównać, gdy delta Dropbox resetuje jego stan). Pliki zawierają również nazwę encji, stan (usunięty / nie usunięty), identyfikator GUID (taki sam jak nazwa pliku), rewizję bazy danych (w celu wykrycia migracji danych lub uniknięcia synchronizacji z nigdy wersjami aplikacji) i oczywiście dane (jeśli wiersz nie zostanie usunięty). dzięki czemu mogę łatwo sprawdzić, które pliki należy załadować, aby uzyskać pełną integralność danych. Synchronizacja rozpoczyna się po wprowadzeniu zmian w podstawowych danych. Jeśli nie ma żadnych zmian, sprawdza zmiany w Dropbox co kilka minut i podczas uruchamiania aplikacji. Dodatkowo, gdy zmiany są wysyłane na serwer, wysyłam transmisję do innych urządzeń, aby poinformować ich o zmianach, aby mogli szybciej synchronizować. Każda zsynchronizowana jednostka ma właściwość GUID (identyfikator GUID służy również jako nazwa pliku dla plików wymiany). Mam również bazę danych Sync, w której przechowuję wersję Dropbox każdego pliku (mogę to porównać, gdy delta Dropbox resetuje jego stan). Pliki zawierają również nazwę encji, stan (usunięty / nie usunięty), identyfikator GUID (taki sam jak nazwa pliku), rewizję bazy danych (w celu wykrycia migracji danych lub uniknięcia synchronizacji z nigdy wersjami aplikacji) i oczywiście dane (jeśli wiersz nie zostanie usunięty). dzięki czemu mogę łatwo sprawdzić, które pliki należy załadować, aby uzyskać pełną integralność danych. Synchronizacja rozpoczyna się po wprowadzeniu zmian w podstawowych danych. Jeśli nie ma żadnych zmian, sprawdza zmiany w Dropbox co kilka minut i podczas uruchamiania aplikacji. Dodatkowo, gdy zmiany są wysyłane na serwer, wysyłam transmisję do innych urządzeń, aby poinformować ich o zmianach, aby mogli szybciej synchronizować. Każda zsynchronizowana jednostka ma właściwość GUID (identyfikator GUID służy również jako nazwa pliku dla plików wymiany). Mam również bazę danych Sync, w której przechowuję wersję Dropbox każdego pliku (mogę to porównać, gdy delta Dropbox resetuje jego stan). Pliki zawierają również nazwę encji, stan (usunięty / nie usunięty), identyfikator GUID (taki sam jak nazwa pliku), rewizję bazy danych (w celu wykrycia migracji danych lub uniknięcia synchronizacji z nigdy wersjami aplikacji) i oczywiście dane (jeśli wiersz nie zostanie usunięty).
To rozwiązanie działa dla tysięcy plików i około 30 podmiotów. Zamiast Dropbox mogłem użyć magazynu kluczy / wartości jako usługi REST, którą chcę zrobić później, ale nie mam na to czasu :) Na razie moim zdaniem moje rozwiązanie jest bardziej niezawodne niż iCloud i, co bardzo ważne, Mam pełną kontrolę nad tym, jak to działa (głównie dlatego, że to mój własny kod).
Innym rozwiązaniem jest zapisywanie zmian MOC jako transakcji - o wiele mniej plików będzie wymienianych z serwerem, ale trudniej jest wykonać początkowe ładowanie w odpowiedniej kolejności do pustych danych podstawowych. iCloud działa w ten sposób, a także inne rozwiązania do synchronizacji mają podobne podejście, np . TICoreDataSync .
-- AKTUALIZACJA
Po pewnym czasie przeprowadziłem migrację do zespołów - polecam to rozwiązanie zamiast wynaleźć koło.
źródło