Bagaimana cara menyinkronkan Data Inti iPhone dengan server web, lalu mendorong ke perangkat lain? [Tutup]

293

Saya telah mengerjakan metode untuk menyinkronkan data inti yang disimpan dalam aplikasi iPhone antara beberapa perangkat, seperti iPad atau Mac. Tidak banyak (jika ada sama sekali) kerangka kerja sinkronisasi untuk digunakan dengan Core Data di iOS. Namun, saya telah memikirkan konsep berikut:

  1. Perubahan dibuat ke penyimpanan data inti lokal, dan perubahan disimpan. (a) Jika perangkat online, ia mencoba untuk mengirim perubahan ke server, termasuk ID perangkat dari perangkat yang mengirim perubahan tersebut. (B) Jika perubahan tidak mencapai server, atau jika perangkat tidak online, aplikasi akan menambahkan perubahan yang diatur ke antrian untuk mengirim ketika itu online.
  2. Server, yang duduk di cloud, menggabungkan set perubahan spesifik yang diterimanya dengan database masternya.
  3. Setelah set perubahan (atau antrian set perubahan) digabungkan pada server cloud, server mendorong semua set perubahan tersebut ke perangkat lain yang terdaftar di server menggunakan semacam sistem polling. (Saya berpikir untuk menggunakan layanan Push Apple, tetapi menurut komentar ternyata ini bukan sistem yang bisa diterapkan.)

Apakah ada hal mewah yang perlu saya pikirkan? Saya telah melihat kerangka kerja REST seperti ObjectiveResource , Core Resource , dan RestfulCoreData . Tentu saja, ini semua bekerja dengan Ruby on Rails, yang saya tidak terikat, tetapi ini adalah tempat untuk memulai. Persyaratan utama yang saya miliki untuk solusi saya adalah:

  1. Setiap perubahan harus dikirim di latar belakang tanpa menghentikan utas utama.
  2. Seharusnya menggunakan bandwidth sesedikit mungkin.

Saya telah memikirkan sejumlah tantangan:

  1. Memastikan bahwa ID objek untuk penyimpanan data yang berbeda pada perangkat yang berbeda terpasang pada server. Artinya, saya akan memiliki tabel ID objek dan ID perangkat, yang diikat melalui referensi ke objek yang disimpan dalam database. Saya akan memiliki catatan (DatabaseId [unik untuk tabel ini], ObjectId [unik untuk item di seluruh database], Datafield1, Datafield2), bidang ObjectId akan merujuk tabel lain, AllObjects: (ObjectId, DeviceId, DeviceObjectId). Kemudian, ketika perangkat mendorong set perubahan, itu akan melewati ID perangkat dan objekId dari objek data inti di penyimpanan data lokal. Kemudian server cloud saya akan memeriksa terhadap objectId dan ID perangkat di tabel AllObjects, dan menemukan catatan untuk berubah di tabel awal.
  2. Semua perubahan harus diberi stempel waktu, sehingga dapat digabungkan.
  3. Perangkat harus menyurvei server, tanpa menggunakan baterai terlalu banyak.
  4. Perangkat lokal juga perlu memperbarui apa pun yang tersimpan dalam memori jika / ketika perubahan diterima dari server.

Apakah ada hal lain yang saya lewatkan di sini? Kerangka kerja seperti apa yang harus saya perhatikan untuk memungkinkan hal ini?

Jason
sumber
5
Anda tidak dapat mengandalkan Pemberitahuan Push yang diterima. Pengguna cukup mengetuknya dan ketika notifikasi kedua tiba, OS melempar yang pertama. Pemberitahuan push IMO adalah cara yang buruk untuk menerima pembaruan sinkronisasi, karena mereka mengganggu pengguna. Aplikasi harus memulai sinkronisasi setiap kali diluncurkan.
Ole Begemann
BAIK. Terima kasih atas informasinya - di luar melakukan polling server secara konstan dan memeriksa pembaruan saat diluncurkan, apakah ada cara bagi perangkat untuk mendapatkan pembaruan? Saya tertarik membuatnya berfungsi jika aplikasi terbuka pada banyak perangkat secara bersamaan.
Jason
1
(Saya tahu sedikit terlambat, tetapi memetikan siapa pun menemukan ini dan juga bertanya-tanya) untuk menjaga beberapa perangkat sinkron secara bersamaan Anda bisa menjaga koneksi terbuka dengan perangkat lain atau server, dan mengirim pesan untuk memberi tahu perangkat lain ) ketika pembaruan terjadi. (mis. cara IRC / olahpesan cepat)
Dan2552
1
@ Dan2552: apa yang Anda gambarkan dikenal sebagai [polling panjang] [ en.wikipedia.org/wiki/… dan merupakan ide bagus, namun koneksi terbuka menghabiskan cukup banyak baterai dan bandwidth pada perangkat seluler.
johndodo
1
Berikut tutorial yang bagus dari Ray Wenderlich tentang cara menyinkronkan data antara aplikasi dan layanan web Anda: raywenderlich.com/15916/…
JRG-Developer

Jawaban:

144

Saya sarankan untuk membaca dan menerapkan strategi sinkronisasi yang dibahas oleh Dan Grover dengan saksama di konferensi iPhone 2009, tersedia di sini sebagai dokumen pdf.

Ini adalah solusi yang layak dan tidak terlalu sulit untuk diterapkan (Dan mengimplementasikan ini di beberapa aplikasinya), tumpang tindih dengan solusi yang dijelaskan oleh Chris. Untuk diskusi teoretis yang mendalam tentang sinkronisasi, lihat makalah dari Russ Cox (MIT) dan William Josephson (Princeton):

Sinkronisasi File dengan Pasangan Waktu Vektor

yang berlaku sama baiknya untuk data inti dengan beberapa modifikasi yang jelas. Ini memberikan strategi sinkronisasi yang jauh lebih kuat dan andal, tetapi membutuhkan lebih banyak upaya untuk diimplementasikan dengan benar.

EDIT:

Tampaknya file pdf Grover tidak lagi tersedia (tautan rusak, Maret 2015). UPDATE: tautan tersedia melalui Way Back Machine di sini

Kerangka Objective-C yang disebut ZSync dan dikembangkan oleh Marcus Zarra telah ditinggalkan, mengingat bahwa iCloud akhirnya tampaknya mendukung sinkronisasi data inti yang benar.

Massimo Cafaro
sumber
Adakah yang memiliki tautan yang diperbarui untuk video ZSync? Juga, apakah ZSync masih dipertahankan? Saya melihat itu terakhir diperbarui pada tahun 2010.
Jeremie Weldin
Komitmen terakhir ZSync pada github adalah pada September 2010 yang membuat saya percaya Marcus berhenti mendukungnya.
Perishable Dave
1
Algoritma yang dijelaskan oleh Dan Grover cukup bagus. Namun, itu tidak akan berfungsi dengan kode server multi-utas (dengan demikian: ini tidak akan skala sama sekali) karena tidak ada cara untuk memastikan klien tidak akan ketinggalan pembaruan ketika waktu digunakan untuk memeriksa pembaruan baru . Tolong, koreksi saya jika saya salah - saya akan membunuh untuk melihat implementasi yang berfungsi ini.
masi
1
@ Patt, saya baru saja mengirim Anda file pdf, seperti yang diminta. Cheers, Massimo Cafaro.
Massimo Cafaro
3
Slide PDF Platform-Sinkronisasi Data Cross-Platform yang hilang oleh Dan Grover dapat diakses melalui Wayback Machine.
Matthew Kairys
272

Saya telah melakukan sesuatu yang mirip dengan apa yang Anda coba lakukan. Biarkan saya memberi tahu Anda apa yang telah saya pelajari dan bagaimana saya melakukannya.

Saya berasumsi Anda memiliki hubungan satu-ke-satu antara objek Data Inti Anda dan model (atau skema db) di server. Anda hanya ingin menjaga konten server tetap sinkron dengan klien, tetapi klien juga dapat memodifikasi dan menambahkan data. Jika saya benar, maka teruslah membaca.

Saya menambahkan empat bidang untuk membantu sinkronisasi:

  1. sync_status - Tambahkan bidang ini hanya untuk model data inti Anda. Ini digunakan oleh aplikasi untuk menentukan apakah Anda memiliki perubahan yang tertunda pada item tersebut. Saya menggunakan kode-kode berikut: 0 berarti tidak ada perubahan, 1 berarti itu antri untuk disinkronkan ke server, dan 2 berarti itu adalah objek sementara dan dapat dibersihkan.
  2. is_deleted - Tambahkan ini ke server dan model data inti. Hapus acara seharusnya tidak benar-benar menghapus baris dari basis data atau dari model klien Anda karena itu membuat Anda tidak dapat menyinkronkan kembali. Dengan memiliki boolean flag sederhana ini, Anda dapat mengatur is_deleted menjadi 1, menyinkronkannya, dan semua orang akan senang. Anda juga harus memodifikasi kode di server dan klien untuk meminta item yang tidak dihapus dengan "is_deleted = 0".
  3. last_modified - Tambahkan ini ke server dan model data inti. Bidang ini harus secara otomatis diperbarui dengan tanggal dan waktu saat ini oleh server setiap kali ada perubahan pada catatan itu. Seharusnya tidak pernah dimodifikasi oleh klien.
  4. guid - Tambahkan bidang id unik global (lihat http://en.wikipedia.org/wiki/Globally_unique_identifier ) ke server dan model data inti. Bidang ini menjadi kunci utama dan menjadi penting saat membuat catatan baru pada klien. Biasanya kunci utama Anda adalah bilangan bulat yang bertambah pada server, tetapi kami harus mengingat bahwa konten dapat dibuat offline dan disinkronkan nanti. GUID memungkinkan kita untuk membuat kunci saat sedang offline.

Pada klien, tambahkan kode untuk mengatur sync_status ke 1 pada objek model Anda setiap kali ada perubahan dan perlu disinkronkan ke server. Objek model baru harus menghasilkan GUID.

Sinkronisasi adalah satu permintaan. Permintaan berisi:

  • Stempel MAX last_modified dari objek model Anda. Ini memberitahu server Anda hanya ingin perubahan setelah cap waktu ini.
  • Array JSON yang berisi semua item dengan sync_status = 1.

Server menerima permintaan dan melakukan ini:

  • Dibutuhkan konten dari array JSON dan memodifikasi atau menambahkan catatan yang dikandungnya. Bidang last_modified diperbarui secara otomatis.
  • Server mengembalikan array JSON yang berisi semua objek dengan cap waktu last_modified lebih besar dari cap waktu yang dikirim dalam permintaan. Ini akan mencakup objek yang baru saja diterima, yang berfungsi sebagai pengakuan bahwa catatan berhasil disinkronkan ke server.

Aplikasi menerima respons dan melakukan ini:

  • Dibutuhkan konten dari array JSON dan memodifikasi atau menambahkan catatan yang dikandungnya. Setiap catatan bisa disetel sync_status 0.

Saya harap itu membantu. Saya menggunakan catatan kata dan model secara bergantian, tetapi saya pikir Anda mendapatkan idenya. Semoga berhasil.

chris
sumber
2
Bidang last_modified juga ada di database lokal, tetapi tidak diperbarui oleh jam iPhone. Sudah diatur oleh server, dan disinkronkan kembali. Tanggal MAX (last_modified) adalah yang dikirimkan aplikasi ke server untuk memerintahkannya mengirim kembali semua yang diubah setelah tanggal tersebut.
chris
3
Nilai global pada klien dapat menggantikan MAX(last_modified), tetapi itu akan menjadi berlebihan karena MAX(last_modified)sudah cukup. Mereka sync_statusmemiliki peran lain. Seperti yang saya tulis sebelumnya, MAX(last_modified)menentukan apa yang perlu disinkronkan dari server, sementara sync_statusmenentukan apa yang perlu disinkronkan ke server.
chris
2
@Flex_Addicted Terima kasih. Ya, Anda perlu mereplikasi bidang untuk setiap entitas yang ingin Anda selaraskan. Namun, Anda harus lebih berhati-hati saat menyinkronkan model dengan suatu hubungan (mis. 1-ke-banyak).
chris
2
@BenPackard - Anda benar. Pendekatan ini tidak melakukan resolusi konflik apa pun sehingga klien terakhir akan menang. Saya belum pernah berurusan dengan ini di aplikasi saya karena catatan diedit oleh satu pengguna. Saya ingin tahu bagaimana Anda menyelesaikan ini.
chris
2
Hai @ tidak, pertimbangkan kasus berikut: Anda membuat perubahan pada objek lokal dan perlu menyinkronkannya kembali ke server. Sinkronisasi hanya dapat terjadi berjam-jam atau berhari-hari kemudian (katakanlah jika Anda sudah offline untuk sementara waktu), dan pada saat itu aplikasi mungkin telah dimatikan dan dimulai kembali beberapa kali. Dalam hal ini metode pada NSManagedObjectContext tidak akan banyak membantu.
chris
11

Jika Anda masih mencari cara untuk pergi, lihat ke ponsel Couchbase. Ini pada dasarnya melakukan semua yang Anda inginkan. ( http://www.couchbase.com/nosql-databases/couchbase-mobile )

radiospiel
sumber
3
Ini hanya melakukan apa yang Anda inginkan jika Anda dapat mengekspresikan data Anda sebagai dokumen daripada data relasional. Ada pekerjaan di sekitar, tetapi mereka tidak selalu cantik atau sepadan.
Jeremie Weldin
dokumen sudah cukup untuk aplikasi kecil
Hai Feng Kao
@radiospiel Tautan Anda rusak
Mick
Ini juga akan menambah ketergantungan yang perlu dituliskan di backend dalam Couchbase DB. Bahkan saya mulai dengan ide NOSQL untuk sinkronisasi tetapi saya tidak dapat membatasi backend saya menjadi NOSQL karena kami memiliki MS SQL yang berjalan di backend.
musim panas
@Mick: sepertinya berfungsi lagi (atau seseorang memperbaiki tautannya? Terima kasih)
radiospiel
7

Mirip seperti @Cris, saya telah mengimplementasikan kelas untuk sinkronisasi antara klien dan server dan menyelesaikan semua masalah yang diketahui sejauh ini (mengirim / menerima data ke / dari server, menggabungkan konflik berdasarkan cap waktu, menghapus entri duplikat dalam kondisi jaringan yang tidak dapat diandalkan, menyinkronkan data bertingkat dan file dll.)

Anda cukup memberi tahu kelas entitas mana dan kolom mana yang harus disinkronkan dan di mana server Anda.

M3Synchronization * syncEntity = [[M3Synchronization alloc] initForClass: @"Car"
                                                              andContext: context
                                                            andServerUrl: kWebsiteUrl
                                             andServerReceiverScriptName: kServerReceiverScript
                                              andServerFetcherScriptName: kServerFetcherScript
                                                    ansSyncedTableFields:@[@"licenceNumber", @"manufacturer", @"model"]
                                                    andUniqueTableFields:@[@"licenceNumber"]];


syncEntity.delegate = self; // delegate should implement onComplete and onError methods
syncEntity.additionalPostParamsDictionary = ... // add some POST params to authenticate current user

[syncEntity sync];

Anda dapat menemukan sumber, contoh kerja dan instruksi lainnya di sini: github.com/knagode/M3Sinkronisasi .

knagode
sumber
Apakah tidak masalah jika kami mengubah waktu perangkat ke nilai abnormal?
Emas
5

Perhatikan pengguna untuk memperbarui data melalui pemberitahuan push. Gunakan utas latar belakang di aplikasi untuk memeriksa data lokal dan data di server cloud, sementara perubahan terjadi di server, ubah data lokal, dan sebaliknya.

Jadi saya pikir bagian yang paling sulit adalah memperkirakan data di sisi mana yang tidak valid.

Semoga ini bisa membantu kamu

Stan
sumber
5

Saya baru saja memposting versi pertama API Penyinkronan Data Cloud Core baru saya, yang dikenal sebagai SynCloud. SynCloud memiliki banyak perbedaan dengan iCloud karena memungkinkan untuk antarmuka sinkronisasi multi-pengguna. Ini juga berbeda dari api sinkronisasi lainnya karena memungkinkan untuk data relasional multi-tabel.

Silakan mencari tahu lebih lanjut di http://www.syncloudapi.com

Dibangun dengan iOS 6 SDK, ini sangat terkini pada 9/27/2012.

logan
sumber
5
Selamat Datang di Stack Overflow! Terima kasih telah mengirim jawaban Anda! Pastikan untuk membaca FAQ tentang Promosi Diri dengan cermat.
Andrew Barber
5

Saya pikir solusi yang baik untuk masalah GUID adalah "sistem ID terdistribusi". Saya tidak yakin apa istilah yang benar, tetapi saya pikir itulah yang digunakan oleh MS SQL server untuk menyebutnya (SQL menggunakan / menggunakan metode ini untuk database terdistribusi / sinkronisasi). Sederhana saja:

Server memberikan semua ID. Setiap kali sinkronisasi dilakukan, hal pertama yang diperiksa adalah "Berapa banyak ID yang tersisa pada klien ini?" Jika klien hampir habis, ia meminta server untuk blok ID baru. Klien kemudian menggunakan ID dalam rentang itu untuk catatan baru. Ini berfungsi baik untuk sebagian besar kebutuhan, jika Anda dapat menetapkan blok yang cukup besar sehingga "tidak" habis sebelum sinkronisasi berikutnya, tetapi tidak terlalu besar sehingga server habis seiring waktu. Jika klien pernah kehabisan, penanganannya bisa sangat sederhana, cukup beri tahu pengguna "maaf Anda tidak dapat menambahkan lebih banyak item sampai Anda menyinkronkan" ... jika mereka menambahkan banyak item, sebaiknya mereka tidak menyinkronkan untuk menghindari data yang sudah basi masalah sih?

Saya pikir ini lebih unggul daripada menggunakan GUID acak karena GUID acak tidak 100% aman, dan biasanya perlu lebih lama dari ID standar (128-bit vs 32-bit). Anda biasanya memiliki indeks berdasarkan ID dan sering menyimpan nomor ID dalam memori, jadi penting untuk tetap kecil.

Tidak benar-benar ingin memposting sebagai jawaban, tetapi saya tidak tahu bahwa ada orang yang akan melihat sebagai komentar, dan saya pikir ini penting untuk topik ini dan tidak termasuk dalam jawaban lain.

Eselk
sumber
2

Pertama, Anda harus memikirkan kembali berapa banyak data, tabel, dan hubungan yang akan Anda miliki. Dalam solusi saya, saya telah menerapkan sinkronisasi melalui file Dropbox. Saya mengamati perubahan di MOC utama dan menyimpan data ini ke file (setiap baris disimpan sebagai gzipped json). Jika ada koneksi internet yang berfungsi, saya memeriksa apakah ada perubahan di Dropbox (Dropbox memberi saya perubahan delta), unduh dan gabungkan (kemenangan terbaru), dan akhirnya masukkan file yang diubah. Sebelum sinkronisasi saya meletakkan file kunci di Dropbox untuk mencegah klien lain menyinkronkan data yang tidak lengkap. Saat mengunduh perubahan, aman bahwa hanya sebagian data yang diunduh (mis. Koneksi internet terputus). Ketika pengunduhan selesai (sepenuhnya atau sebagian) mulai memuat file ke dalam Data Inti. Ketika ada hubungan yang tidak terselesaikan (tidak semua file diunduh) itu berhenti memuat file dan mencoba untuk menyelesaikan mengunduh nanti. Relasi disimpan hanya sebagai GUID, jadi saya dapat dengan mudah memeriksa file mana yang dimuat agar memiliki integritas data penuh. Sinkronisasi dimulai setelah perubahan data inti dilakukan. Jika tidak ada perubahan, selain memeriksa perubahan di Dropbox setiap beberapa menit dan pada startup aplikasi. Tambahan pula ketika perubahan dikirim ke server saya mengirim siaran ke perangkat lain untuk memberi tahu mereka tentang perubahan, sehingga mereka dapat melakukan sinkronisasi lebih cepat. Setiap entitas yang disinkronkan memiliki properti GUID (panduan juga digunakan sebagai nama file untuk bertukar file). Saya juga menyinkronkan basis data tempat saya menyimpan revisi Dropbox untuk setiap file (saya dapat membandingkannya ketika delta Dropbox menyetel ulang statusnya). File juga mengandung nama entitas, status (dihapus / tidak dihapus), panduan (sama dengan nama file), revisi basis data (untuk mendeteksi migrasi data atau untuk menghindari sinkronisasi dengan versi aplikasi yang tidak pernah) dan tentu saja data (jika baris tidak dihapus). jadi saya bisa dengan mudah memeriksa file mana yang akan dimuat untuk memiliki integritas data penuh. Sinkronisasi dimulai setelah perubahan data inti dilakukan. Jika tidak ada perubahan, selain memeriksa perubahan di Dropbox setiap beberapa menit dan pada startup aplikasi. Tambahan pula ketika perubahan dikirim ke server saya mengirim siaran ke perangkat lain untuk memberi tahu mereka tentang perubahan, sehingga mereka dapat melakukan sinkronisasi lebih cepat. Setiap entitas yang disinkronkan memiliki properti GUID (panduan juga digunakan sebagai nama file untuk bertukar file). Saya juga menyinkronkan basis data tempat saya menyimpan revisi Dropbox untuk setiap file (saya dapat membandingkannya ketika delta Dropbox menyetel ulang statusnya). File juga mengandung nama entitas, status (dihapus / tidak dihapus), panduan (sama dengan nama file), revisi basis data (untuk mendeteksi migrasi data atau untuk menghindari sinkronisasi dengan versi aplikasi yang tidak pernah) dan tentu saja data (jika baris tidak dihapus). jadi saya bisa dengan mudah memeriksa file mana yang akan dimuat untuk memiliki integritas data penuh. Sinkronisasi dimulai setelah perubahan data inti dilakukan. Jika tidak ada perubahan, selain memeriksa perubahan di Dropbox setiap beberapa menit dan pada startup aplikasi. Tambahan pula ketika perubahan dikirim ke server saya mengirim siaran ke perangkat lain untuk memberi tahu mereka tentang perubahan, sehingga mereka dapat melakukan sinkronisasi lebih cepat. Setiap entitas yang disinkronkan memiliki properti GUID (panduan juga digunakan sebagai nama file untuk bertukar file). Saya juga menyinkronkan basis data tempat saya menyimpan revisi Dropbox untuk setiap file (saya dapat membandingkannya ketika delta Dropbox menyetel ulang statusnya). File juga mengandung nama entitas, status (dihapus / tidak dihapus), panduan (sama dengan nama file), revisi basis data (untuk mendeteksi migrasi data atau untuk menghindari sinkronisasi dengan versi aplikasi yang tidak pernah) dan tentu saja data (jika baris tidak dihapus).

Solusi ini berfungsi untuk ribuan file dan sekitar 30 entitas. Alih-alih Dropbox saya bisa menggunakan key / value store sebagai layanan web REST yang ingin saya lakukan nanti, tetapi tidak punya waktu untuk ini :) Untuk saat ini, menurut saya, solusi saya lebih dapat diandalkan daripada iCloud dan, yang sangat penting, Saya memiliki kontrol penuh tentang cara kerjanya (terutama karena itu kode saya sendiri).

Solusi lain adalah menyimpan perubahan MOC sebagai transaksi - akan ada jauh lebih sedikit file yang dipertukarkan dengan server, tetapi lebih sulit untuk melakukan pemuatan awal dalam urutan yang benar ke dalam data inti yang kosong. iCloud bekerja dengan cara ini, dan juga solusi sinkronisasi lainnya memiliki pendekatan yang serupa, misalnya TICoreDataSync .

- PEMBARUAN

Setelah beberapa saat, saya pindah ke Ensembles - Saya merekomendasikan solusi ini untuk menemukan kembali roda.

thom_ek
sumber