在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ iOS/ 數(shù)據(jù)同步
與四軸無人機(jī)的通訊
在沙盒中編寫腳本
結(jié)構(gòu)體和值類型
深入理解 CocoaPods
UICollectionView + UIKit 力學(xué)
NSString 與 Unicode
代碼簽名探析
測(cè)試
架構(gòu)
第二期-并發(fā)編程
Metal
自定義控件
iOS 中的行為
行為驅(qū)動(dòng)開發(fā)
Collection View 動(dòng)畫
截圖測(cè)試
MVVM 介紹
使 Mac 應(yīng)用數(shù)據(jù)腳本化
一個(gè)完整的 Core Data 應(yīng)用
插件
字符串
為 iOS 建立 Travis CI
先進(jìn)的自動(dòng)布局工具箱
動(dòng)畫
為 iOS 7 重新設(shè)計(jì) App
XPC
從 NSURLConnection 到 NSURLSession
Core Data 網(wǎng)絡(luò)應(yīng)用實(shí)例
GPU 加速下的圖像處理
自定義 Core Data 遷移
子類
與調(diào)試器共舞 - LLDB 的華爾茲
圖片格式
并發(fā)編程:API 及挑戰(zhàn)
IP,TCP 和 HTTP
動(dòng)畫解釋
響應(yīng)式 Android 應(yīng)用
初識(shí) TextKit
客戶端
View-Layer 協(xié)作
回到 Mac
Android
Core Image 介紹
自定義 Formatters
Scene Kit
調(diào)試
項(xiàng)目介紹
Swift 的強(qiáng)大之處
測(cè)試并發(fā)程序
Android 通知中心
調(diào)試:案例學(xué)習(xí)
從 UIKit 到 AppKit
iOS 7 : 隱藏技巧和變通之道
安全
底層并發(fā) API
消息傳遞機(jī)制
更輕量的 View Controllers
用 SQLite 和 FMDB 替代 Core Data
字符串解析
終身學(xué)習(xí)的一代人
視頻
Playground 快速原型制作
Omni 內(nèi)部
同步數(shù)據(jù)
設(shè)計(jì)優(yōu)雅的移動(dòng)游戲
繪制像素到屏幕上
相機(jī)與照片
音頻 API 一覽
交互式動(dòng)畫
常見的后臺(tái)實(shí)踐
糟糕的測(cè)試
避免濫用單例
數(shù)據(jù)模型和模型對(duì)象
Core Data
字符串本地化
View Controller 轉(zhuǎn)場(chǎng)
照片框架
響應(yīng)式視圖
Square Register 中的擴(kuò)張
DTrace
基礎(chǔ)集合類
視頻工具箱和硬件加速
字符串渲染
讓東西變得不那么糟
游戲中的多點(diǎn)互聯(lián)
iCloud 和 Core Data
Views
虛擬音域 - 聲音設(shè)計(jì)的藝術(shù)
導(dǎo)航應(yīng)用
線程安全類的設(shè)計(jì)
置換測(cè)試: Mock, Stub 和其他
Build 工具
KVC 和 KVO
Core Image 和視頻
Android Intents
在 iOS 上捕獲視頻
四軸無人機(jī)項(xiàng)目
Mach-O 可執(zhí)行文件
UI 測(cè)試
值對(duì)象
活動(dòng)追蹤
依賴注入
Swift
項(xiàng)目管理
整潔的 Table View 代碼
Swift 方法的多面性
為什么今天安全仍然重要
Core Data 概述
Foundation
Swift 的函數(shù)式 API
iOS 7 的多任務(wù)
自定義 Collection View 布局
測(cè)試 View Controllers
訪談
收據(jù)驗(yàn)證
數(shù)據(jù)同步
自定義 ViewController 容器轉(zhuǎn)場(chǎng)
游戲
調(diào)試核對(duì)清單
View Controller 容器
學(xué)無止境
XCTest 測(cè)試實(shí)戰(zhàn)
iOS 7
Layer 中自定義屬性的動(dòng)畫
第一期-更輕量的 View Controllers
精通 iCloud 文檔存儲(chǔ)
代碼審查的藝術(shù):Dropbox 的故事
GPU 加速下的圖像視覺
Artsy
照片擴(kuò)展
理解 Scroll Views
使用 VIPER 構(gòu)建 iOS 應(yīng)用
Android 中的 SQLite 數(shù)據(jù)庫支持
Fetch 請(qǐng)求
導(dǎo)入大數(shù)據(jù)集
iOS 開發(fā)者的 Android 第一課
iOS 上的相機(jī)捕捉
語言標(biāo)簽
同步案例學(xué)習(xí)
依賴注入和注解,為什么 Java 比你想象的要好
編譯器
基于 OpenCV 的人臉識(shí)別
玩轉(zhuǎn)字符串
相機(jī)工作原理
Build 過程

數(shù)據(jù)同步


仔細(xì)考慮同步,否則同步將是痛苦。

不是蘇斯博士說的 (蘇斯博士是美國著名兒童文學(xué)和圖書作家)

同步是軟件開發(fā)中的一項(xiàng)基本要素。它包括很多種形式,從強(qiáng)制使用不同設(shè)備上的時(shí)鐘來協(xié)商它們之間的延遲,到使用 @synchronized 代碼塊來序列化訪問多線程編程中的資源。

本文,我將要介紹多種 數(shù)據(jù)同步 的方法,接下來本文將使用 同步 (sync) 代替數(shù)據(jù)同步 (data synchronization)。簡(jiǎn)單來說,問題就在于:如何存儲(chǔ)時(shí)間和空間上分離的兩部分?jǐn)?shù)據(jù),讓這兩部分的數(shù)據(jù)盡可能的相同。

我個(gè)人的興趣要追溯到早期的 iOS App Store,那時(shí),同步在我的生活中扮演了重要的角色。當(dāng)時(shí),我是學(xué)習(xí)卡片應(yīng)用程序 Mental Case 的開發(fā)者。由于包括 Mac 版、 iPad 版和 iPhone 版, Mental Case 更像是一套而不是單個(gè)應(yīng)用,并且它的一大特色就是能夠在不同的設(shè)備之間同步你的學(xué)習(xí)資料。最初,在以數(shù)據(jù)為中心的年代。 Mental Case 將 Mac 作為中心,通過本地 Wi-Fi 網(wǎng)絡(luò),和一個(gè)或者多個(gè) iOS 設(shè)備同步數(shù)據(jù)。現(xiàn)在, Mental Case 系列應(yīng)用通過 iCloud 進(jìn)行點(diǎn)到點(diǎn) (peer-to-peer) 的數(shù)據(jù)同步。

合理地實(shí)現(xiàn)數(shù)據(jù)同步是有挑戰(zhàn)的,但是更大的問題是專業(yè)化而不是開發(fā)一個(gè)通用的 Web 服務(wù),然后這就要考慮更專業(yè)的解決方案。比如,當(dāng)一類 Web 服務(wù)總是需要服務(wù)端的開發(fā)的時(shí)候,使用一種同步框架能夠在你現(xiàn)有的代碼基礎(chǔ)上做最少的改變,并且完全不需要服務(wù)端的代碼。

在下文中,我將介紹在移動(dòng)設(shè)備早期出現(xiàn)的多種數(shù)據(jù)同步的方法,在高級(jí)層面上解釋它們的工作原理,并給出一些他們的最佳使用指導(dǎo)。我還將根據(jù)當(dāng)今的形勢(shì),描繪一些數(shù)據(jù)同步領(lǐng)域的新趨勢(shì)。

簡(jiǎn)史

在開始介紹多種數(shù)據(jù)同步方法的細(xì)節(jié)之前,有必要了解它的演變過程以及如何適應(yīng)早期的技術(shù)帶來的限制的。

就消費(fèi)設(shè)備而言,數(shù)據(jù)同步始于有線連接。上世紀(jì) 90 年代末和 21 世紀(jì)初,像 Palm PilotiPod 這樣的外圍設(shè)備能夠通過火線 (Firewire) 或者 USB 和 Mac 或者 PC 進(jìn)行同步。蘋果的數(shù)字中心策略正是基于這種方法。后來,由于網(wǎng)速的提升,Wi-Fi 和藍(lán)牙在一定程度上增補(bǔ)了有線連接,但是 iTunes 現(xiàn)在仍然使用這種方式。

由于 21 世紀(jì)云服務(wù)的飛速發(fā)展,由 Mac 或者 PC 作為中心的方式已經(jīng)逐步轉(zhuǎn)向了云。云的優(yōu)勢(shì)在于無論什么時(shí)候,只要設(shè)備有網(wǎng)絡(luò),它就可以使用。有了基于云的數(shù)據(jù)同步,你再也不用呆在家里的電腦旁邊進(jìn)行同步數(shù)據(jù)了。

上面提到的每一種方式都在設(shè)備間利用了我稱之為 同步通訊 (Synchronous Communication, SC)的概念。你的 iPhone 上的一個(gè)應(yīng)用直接和一臺(tái) Mac 或者云服務(wù)通訊,然后實(shí)時(shí)地接收返回的數(shù)據(jù)。

現(xiàn)在,出現(xiàn)了一種新興的基于 異步通訊 (Asynchronous Communication, AC) 的數(shù)據(jù)同步方式。應(yīng)用不再直接和云“通話”,而是和一個(gè)框架或者本地的文件系統(tǒng)交換數(shù)據(jù)。應(yīng)用程序不再期望立刻得到回應(yīng),取而代之的是,數(shù)據(jù)是在后臺(tái)和云端進(jìn)行交互了。

這種方式將應(yīng)用程序代碼和數(shù)據(jù)同步過程解耦,將開發(fā)者從精確操縱數(shù)據(jù)同步中解放出來。遵循這一新趨勢(shì)的產(chǎn)品范例有蘋果的 Core Data-iCloud 框架,Dropbox Datastore API,甚至像 TouchDB (基于 CouchDB project)那樣的文件存儲(chǔ)。

數(shù)據(jù)同步的這段歷史并不是遵循一個(gè)單一的線性路徑。每個(gè)階段都是先遵循,后使用,再創(chuàng)新的更迭演化。今天,所有的這些技術(shù)仍然存在并且仍在使用,并且他們中的每一個(gè)都有可能是你的某個(gè)特定問題的合適的解決方案。

同步網(wǎng)格

我們已經(jīng)知道數(shù)據(jù)同步的方式可以根據(jù)它們是否使用了同步通訊來分類,但是也能夠根據(jù)與客戶端交互是否使用了“智能”服務(wù)器,或者同步過程是否采用以客戶端處理復(fù)雜事情的對(duì)等方式。下面這個(gè)簡(jiǎn)單的表格列出了所有的同步技術(shù):

同步 異步
客戶端-服務(wù)端 Parse
StackMob
Windows Azure Mobile Services
Helios
Custom Web Service
Dropbox Datastore
TouchDB
Wasabi Sync
Zumero
對(duì)等方式 iTunes/iPod
Palm Pilot
Core Data with iCloud
TICoreDataSync
Core Data Ensembles

同步對(duì)等網(wǎng)絡(luò) (Synchronous Peer-to-Peer, S-P2P) 是實(shí)際上第一個(gè)被廣泛接收的方式,并被用于像 iPod 和 PDA 這樣的外圍設(shè)備。S-P2P 實(shí)現(xiàn)簡(jiǎn)單并且本地網(wǎng)絡(luò)速度快。由于 iTunes 需要傳輸大量的媒體介質(zhì),所以 iTunes 仍然使用這種方式。

http://wiki.jikexueyuan.com/project/objc/images/10-1.png" alt="" />

Synchronous Peer-to-Peer (S-P2P)

同步客戶端服務(wù)器 (Synchronous Client-Server, S-CS) 方式隨著網(wǎng)絡(luò)的發(fā)展以及像亞馬遜云服務(wù) (AWS) 這樣的云服務(wù)的流行而變得流行起來。S-CS 可能是當(dāng)今最常用的同步方式。站在實(shí)現(xiàn)的立場(chǎng)上,它和開發(fā)任何其他的 web 服務(wù)非常相似。典型地,一個(gè)自定義的云應(yīng)用程序使用某種語言開發(fā),該全棧式開發(fā)框架可能和客戶端程序無關(guān),比如 Ruby on Rails, Django,或者 Node.js。與云通訊的速度要比本地網(wǎng)絡(luò)慢,但是 S-CS 有一個(gè)優(yōu)勢(shì)叫做“始終在線”,因此,只要網(wǎng)絡(luò)保持連接,客戶端可以在任何位置同步數(shù)據(jù)。

http://wiki.jikexueyuan.com/project/objc/images/10-2.png" alt="" />

Synchronous Client-Server (S-CS)

對(duì)于異步客戶端服務(wù)器 (Asynchronous Client-Server, A-CS) 方式,開發(fā)者使用數(shù)據(jù)存儲(chǔ)的 API,存取本地備份的數(shù)據(jù)。同步數(shù)據(jù)的過程透明地發(fā)生在后臺(tái),應(yīng)用程序代碼通過回調(diào)機(jī)制被告知是否發(fā)生變化。采用這種方式的的例子包括 Dropbox Datastore API,以及對(duì) Core Data 開發(fā)者來說的 Wasabi Sync 服務(wù)。

異步 冗余同步 方式的一個(gè)優(yōu)點(diǎn)是當(dāng)網(wǎng)絡(luò)不可用的時(shí)候,應(yīng)用程序可以繼續(xù)工作并能夠存取用戶數(shù)據(jù)。另一個(gè)優(yōu)點(diǎn)是開發(fā)者不用再關(guān)注通訊和同步的細(xì)節(jié),可以集中精力在應(yīng)用程序的其他方面,數(shù)據(jù)存儲(chǔ)看上去就好像是在設(shè)備本地進(jìn)行的。

http://wiki.jikexueyuan.com/project/objc/images/10-3.png" alt="" />

Asynchronous Client-Server (A-CS)

異步對(duì)等方式 (Asynchronous Peer-to-Peer, A-P2P) 目前尚在初期,并且沒有被廣泛地使用。A-P2P 將所有的負(fù)載分發(fā)到客戶端程序上,并且不使用直接通訊。開發(fā)一個(gè) A-P2P 框架是比較復(fù)雜的,并且導(dǎo)致了一些眾所周知的問題,包括蘋果早期想讓 iCloud 支持 Core Data (現(xiàn)在已經(jīng)支持的很好了)。和 S-CS 一樣,每一個(gè)設(shè)備都有一份數(shù)據(jù)存儲(chǔ)的完整副本。通過交換不同設(shè)備之間的文件的變化來實(shí)現(xiàn)數(shù)據(jù)同步,這些文件通常被稱為 事務(wù)日志 。事務(wù)日志被上傳到云端,然后從云端通過一個(gè)基本的文件處理服務(wù)器 (比如 iCloud, Dropbox) 分發(fā)給其他設(shè)備,這一過程不需要知道日志的具體內(nèi)容。

http://wiki.jikexueyuan.com/project/objc/images/10-4.png" alt="" />

Asynchronous Peer-to-Peer (A-P2P)

鑒于開發(fā) A-P2P 系統(tǒng)的復(fù)雜性,你也許會(huì)問為什么我們還要自找麻煩地去開發(fā)。A-P2P 框架的一個(gè)主要優(yōu)勢(shì)是它抽離了對(duì)智能服務(wù)器的需求。開發(fā)者能夠不用考慮服務(wù)端的開發(fā),并可以利用多種可用的文件傳輸服務(wù)的優(yōu)勢(shì),他們其中的大多數(shù)是免費(fèi)的。而且,由于 A-P2P 系統(tǒng)不連接到一個(gè)特定的服務(wù),也就沒有了供應(yīng)商被鎖定的危險(xiǎn)。

數(shù)據(jù)同步的要素

介紹完了不同種類的數(shù)據(jù)同步算法,我現(xiàn)在想介紹一下這些算法的常用組件。你可以想一想如何操控一個(gè)孤立的應(yīng)用程序。

所有的同步方法都有一些共同的要素,包括:

  • 能夠在整個(gè)存儲(chǔ)中識(shí)別出相應(yīng)的對(duì)象
  • 確定自上一次同步之后發(fā)生了哪些變化
  • 解決由并發(fā)變化引起的沖突

在接下來的部分,在繼續(xù)介紹如何實(shí)現(xiàn)這些算法細(xì)節(jié)之前,我想先介紹這些要素。

識(shí)別

在只有一個(gè)數(shù)據(jù)存儲(chǔ)的獨(dú)立應(yīng)用程序中,對(duì)象的識(shí)別典型地可以使用數(shù)據(jù)庫表的行索引,或者在 Core Data 中與之類似的東西,比如 NSManagedObjectID,這些識(shí)別的方法只特定地適用于本地存儲(chǔ),并不適合在不同的設(shè)備之間識(shí)別相應(yīng)的對(duì)象。當(dāng)應(yīng)用程序同步的時(shí)候,很重要的一點(diǎn)就是在不同存儲(chǔ)中的對(duì)象能夠與其他的對(duì)象相互關(guān)聯(lián),因此需要 全局標(biāo)識(shí)符 。

全局標(biāo)識(shí)符通常就是 Universally Unique Identifiers (UUIDs);不同存儲(chǔ)中的對(duì)象,如果具有相同全局標(biāo)識(shí)符,則可以認(rèn)為在邏輯上代表一個(gè)單一實(shí)例。對(duì)一個(gè)對(duì)象的修改最后會(huì)導(dǎo)致相應(yīng)的對(duì)象也會(huì)被更新。(UUIDs 可以由 Cocoa 最近添加的 NSUUID 類來創(chuàng)建,或者經(jīng)常被遺忘的 NSProcessInfo 類的 globallyUniqueString 方法)。

UUIDs 并不是對(duì)所有的對(duì)象都適用。比如,它就不太適合那些有固定成員集合的類的對(duì)象。一個(gè)一般的例子是一個(gè)單例對(duì)象,只有一個(gè)可能的對(duì)象被允許。另外一個(gè)例子是唯一表示是字符串的類標(biāo)簽 (tag-like) 對(duì)象。

但是一個(gè)類決定了對(duì)象標(biāo)識(shí),重要的是它能在全局標(biāo)識(shí)符中被反映出來。邏輯上相同的對(duì)象在不同的存儲(chǔ)中應(yīng)該具有相同的標(biāo)識(shí)符,并且不相同的對(duì)象應(yīng)該具有不相同的標(biāo)識(shí)符。

變化追蹤

變化追蹤 用來描述同步算法如何確定自上一次同步后,數(shù)據(jù)發(fā)生了哪些變化,然后本地存儲(chǔ)應(yīng)該如何修改。對(duì)象的每一次修改 (通常稱為 增量) 通常是一個(gè) CRUD 操作:創(chuàng)建 (creation),讀取 (read),更新 (update),刪除 (deletion)。

我們面臨的第一個(gè)選擇就是要選擇記錄粒度的大小。當(dāng)任何單個(gè)屬性變化的時(shí)候,是應(yīng)該更新實(shí)體里的全部屬性呢?還是只記錄被修改的屬性。正確的選擇也許不同;我將會(huì)在研究細(xì)節(jié)的時(shí)候更多地討論這一話題。

在任何一種情況下,你需要一種方法來記錄變化。在最簡(jiǎn)單的情形下,本地存儲(chǔ)里可能就是一個(gè) Boolean 型屬性來標(biāo)識(shí)一個(gè)對(duì)象是不是新的,或者自上一次更新后有沒有被更新。在更高級(jí)的算法中,變化被記錄在主存儲(chǔ)之外,以字典的方式記錄被修改的屬性并有一個(gè)與之相關(guān)聯(lián)的時(shí)間戳。

沖突解決

當(dāng)邏輯上相同的數(shù)據(jù)集有兩個(gè)或更多的存儲(chǔ)時(shí),潛在的 沖突 就可能出現(xiàn)。沒有同步的情況下,修改一個(gè)存儲(chǔ)里某個(gè)對(duì)象,與修改另一個(gè)存儲(chǔ)中與之相對(duì)應(yīng)的對(duì)象,這兩件事可能同時(shí)發(fā)生。這些改變同時(shí)發(fā)生,一些行為可能就會(huì)留下一些沖突的對(duì)象,一旦數(shù)據(jù)同步,合法的狀態(tài)就會(huì)出現(xiàn)在所有的存儲(chǔ)中。

在最簡(jiǎn)單的世界里,讀寫存儲(chǔ)可以被認(rèn)為是原子操作,因此解決沖突就可以簡(jiǎn)單地看成選擇什么版本的存儲(chǔ)。這也許比你想的要普通的多。比如,iCloud 對(duì)文檔的同步就是用的這種方式:當(dāng)發(fā)生沖突的時(shí)候,將詢問用戶希望存儲(chǔ)哪個(gè)版本 — 這沒有合并有沖突的存儲(chǔ)之間的變化。

當(dāng)解決沖突的時(shí)候,有很多種方法來決定優(yōu)先考慮哪些變化。如果你使用了一個(gè)中央服務(wù)器,那么最直接的方式就是假設(shè)最近的一次同步操作級(jí)別最高。所有在這一次同步操作中的變化將覆蓋之前存儲(chǔ)的數(shù)據(jù)。復(fù)雜一點(diǎn)的系統(tǒng)會(huì)比較沖突發(fā)生的時(shí)候的時(shí)間戳然后選擇最近的一次。

沖突解決可能會(huì)比較棘手,如果你已經(jīng)有了選擇,你應(yīng)該避免設(shè)計(jì)一個(gè)模型僅僅是讓它們變得合法。在一個(gè)新的項(xiàng)目中,這比思考所有可能出現(xiàn)的的無效狀態(tài)要容易的多。

關(guān)系可能是非常麻煩的 (這可不是對(duì)人際交往的評(píng)價(jià))。拿一個(gè)實(shí)體 A 和實(shí)體 B 之間簡(jiǎn)單的一對(duì)一的關(guān)系舉例。假設(shè) 設(shè)備1設(shè)備2 都擁有對(duì)象 A[1],和與之相關(guān)的對(duì)象 B[1]。設(shè)備1 創(chuàng)建了一個(gè)對(duì)象 B[2],并將 A[1]B[2] 相關(guān)聯(lián),然后刪除 B[1]。同時(shí),設(shè)備2 也刪除 B[1],但是創(chuàng)建了 B[3],并將 B[3]A[1] 關(guān)聯(lián)。

http://wiki.jikexueyuan.com/project/objc/images/10-5.png" alt="" />

Orphaned object arising from conflicting changes to a one-to-one relationship.

同步之后,將會(huì)出現(xiàn)一個(gè)額外的,孤立的,不和任何對(duì)象 A 相關(guān)聯(lián)的對(duì)象 B。如果關(guān)系需要一個(gè)驗(yàn)證規(guī)則,那么你就得到了一個(gè)無效對(duì)象圖。而這僅僅是你能想到的最簡(jiǎn)單的一種關(guān)系。當(dāng)涉及到更復(fù)雜的關(guān)系時(shí),還可能會(huì)出現(xiàn)更多的問題。

但是這樣的沖突都解決了,對(duì)我們的信息還是有決定性重大幫助的。如果同樣的場(chǎng)景發(fā)生在兩臺(tái)不同的設(shè)備上,就應(yīng)該使用同樣的辦法解決。

這看上去可能顯而易見,但是很容易出錯(cuò)。還是上面那個(gè)例子,如果你的方案是隨機(jī)的選擇對(duì)象 B 中的一個(gè)刪除,在某種情況下,兩個(gè)設(shè)備可能會(huì)刪除不同的對(duì)象,那么最后就完全沒有對(duì)象 B 了。你應(yīng)該力爭(zhēng)在每個(gè)設(shè)備中刪除對(duì)應(yīng)的對(duì)象 B 。這是可以實(shí)現(xiàn)的,可以首先對(duì)對(duì)象排序,然后總是選擇相同的對(duì)象。

對(duì)等同步通訊(S-P2P)

既然我們已經(jīng)了解了所有同步算法的基本要素,接下來,就更詳細(xì)的看一看之前介紹的每一種特定的方式,首先介紹同步 (SC) 通訊方法。

我們從最簡(jiǎn)單的可工作的 S-P2P 方案開始。假設(shè)我們有一個(gè)像 iTunes 那樣的 Mac 應(yīng)用程序,它可以通過 USB、藍(lán)牙或者 Wi-Fi 和 iPhone 進(jìn)行同步通訊。憑借快速的本地網(wǎng)絡(luò),我們不用太在意限制數(shù)據(jù)傳輸,所以我們可以在這方面偷點(diǎn)懶。

當(dāng) iPhone 第一次同步的時(shí)候,兩個(gè)應(yīng)用程序通過 Bonjour 發(fā)現(xiàn)對(duì)方,然后 Mac 應(yīng)用程序?qū)⑺乃写鎯?chǔ)數(shù)據(jù)壓縮,通過套接字將壓縮后的文件傳遞給 iPhone 應(yīng)用程序,然后 iPhone 將其解壓并安裝。

現(xiàn)在假設(shè)用戶使用 iPhone 對(duì)已經(jīng)存在的對(duì)象做了修改 (比如,給一首歌打了星級(jí))。該設(shè)備上的應(yīng)用程序給該對(duì)象設(shè)置了一個(gè) Boolean 型的標(biāo)記(比如,changedSinceSync),用來表示該對(duì)象是新的還是已經(jīng)被修改過的。

當(dāng)下一次同步發(fā)生的時(shí)候,iPhone 應(yīng)用程序?qū)⑺乃袛?shù)據(jù)存儲(chǔ)壓縮并回發(fā)給 Mac。Mac 裝載這些數(shù)據(jù),尋找被修改的實(shí)例,然后更新它自己對(duì)應(yīng)的數(shù)據(jù)。然后 Mac 又將更新后的數(shù)據(jù)存儲(chǔ)的完整拷貝發(fā)送給 iPhone,用來替代 iPhone 已經(jīng)存在的數(shù)據(jù)存儲(chǔ),然后整個(gè)流程又重新開始。

雖然還有很多變化和改進(jìn)的可能,但是這的確是一個(gè)可行的方案,并且適用于很多應(yīng)用程序??偨Y(jié)來說,同步操作需要設(shè)備能夠向其他設(shè)備傳輸數(shù)據(jù),并且能夠決定哪些被修改、合并,然后回傳更新后的數(shù)據(jù)。你保證了這兩個(gè)設(shè)備同步之后具有相同的數(shù)據(jù),所以,有很強(qiáng)的健壯性。

客戶端-服務(wù)器同步通訊(S-CS)

當(dāng)?shù)仁街屑尤肓朔?wù)器的時(shí)候,事情變得微妙起來。服務(wù)器是為了能夠更加靈活地同步數(shù)據(jù),但是它是以數(shù)據(jù)傳輸和存儲(chǔ)為代價(jià)的。我們需要盡可能地減少通訊開銷,所以來回地拷貝整個(gè)數(shù)據(jù)是不可行的。

這一次,我還是把重點(diǎn)放在最簡(jiǎn)單可行的方案上。假設(shè)數(shù)據(jù)存儲(chǔ)在服務(wù)器上的數(shù)據(jù)庫中,并且每一個(gè)對(duì)象都有一個(gè)最后更新的時(shí)間戳。當(dāng)客戶端程序第一次同步的時(shí)候,它以序列化 (比如 JSON)的形式下載所有的數(shù)據(jù),然后建立一個(gè)本地存儲(chǔ)。它同樣也在本地記錄了同步的時(shí)間戳。

當(dāng)客戶端程序發(fā)生改變的時(shí)候,它會(huì)更新對(duì)象的最后更新時(shí)間戳。服務(wù)器也會(huì)做同樣的事情,其他設(shè)備也應(yīng)該在這個(gè)過渡期里同步。

當(dāng)下一次同步發(fā)生的時(shí)候,客戶端會(huì)決定自上一次同步后,哪些對(duì)象做了修改,然后僅把被修改的對(duì)象發(fā)送給服務(wù)器。服務(wù)器會(huì)合并這些修改。如果服務(wù)器對(duì)某一個(gè)對(duì)象的拷貝被另一個(gè)客戶端做了修改,那么它會(huì)以最近的時(shí)間戳為準(zhǔn)來保存修改。

然后服務(wù)器會(huì)回傳所有比上一次從客戶端發(fā)來的時(shí)間戳新的變化。這需要考慮到合并的問題,刪除所有覆蓋的變化。

也許有很多不同的方法。比如,你可以為每一個(gè)個(gè)人屬性引入一個(gè)時(shí)間戳,然后在粒度級(jí)去追蹤變化。或者你可以在客戶端合并所有的數(shù)據(jù),然后將合并后的結(jié)果發(fā)回給服務(wù)器,這實(shí)際上是互換了角色。但是,基本說來,一個(gè)設(shè)備發(fā)送修改結(jié)果給其他設(shè)備,然后接收方合并并回發(fā)合并后的結(jié)果。

刪除需要考慮更多。因?yàn)橐坏┠銊h除了一個(gè)對(duì)象,你就不可能跟蹤它了。一種選擇是使用 軟刪除 ,也就是對(duì)象并不是被真正的刪除,而是標(biāo)記為刪除 (比如使用一個(gè) Boolean 屬性)。(這和在 Finder 中刪除一個(gè)文件類似。只有當(dāng)你清空的垃圾桶之后,它才被永久地刪除。)

客戶端-服務(wù)器異步通訊 (A-CS)

異步的數(shù)據(jù)同步框架和服務(wù)的吸引力在于它們提供了現(xiàn)成的解決方案。上文提到的同步的數(shù)據(jù)同步方案是要定制的—也就是說你不得不為每一個(gè)應(yīng)用程序?qū)懞芏嗟淖远x代碼。另外,使用 S-CS 架構(gòu),你不得不在所有的平臺(tái)間復(fù)制類似的功能,來保持服務(wù)器的操作。而這需要的技能是大多數(shù) Objective-C 開發(fā)者所不具備的。

異步服務(wù) (比如, Dropbox Datastore APIWasabi Sync 通常提供的框架,讓應(yīng)用程序開發(fā)者用起來好像是本地?cái)?shù)據(jù)存儲(chǔ)。這些框架在本地保存修改,然后在后臺(tái)控制與服務(wù)器的同步。

A-CS 和 S-CS 的一個(gè)最主要的區(qū)別在于,A-CS 框架額外提供的抽象層,屏蔽了直接參與同步的客戶端代碼。這也意味著,同一服務(wù)可以用于所有的數(shù)據(jù)模型,而不是特定的一種模型。

對(duì)等異步通訊(A-P2P)

A-P2P 是最沒有被充分開發(fā)的方式,因?yàn)樗彩亲铍y實(shí)現(xiàn)的。但是它的承諾是偉大的,因?yàn)樗?A-CS 在后端更加抽象,使得一個(gè)獨(dú)立的應(yīng)用程序能夠通過不同的服務(wù)進(jìn)行同步。

盡管沒有被充分開發(fā),但還是有應(yīng)用程序已經(jīng)在使用這種方式。比如,著名的待辦事項(xiàng)軟件 Clear 就自己實(shí)現(xiàn)了 A-P2P,通過 iCloud 進(jìn)行同步,并且有在線文檔。還有一些框架像蘋果的 Core Data—iCloud 集成, TICoreDataSync 以及 Core Data Ensembles 均采用這種方式并且逐漸被使用。

作為一個(gè)應(yīng)用程序開發(fā)者,你不需要過多關(guān)心一個(gè) A-P2P 系統(tǒng)是如何工作的 — 錯(cuò)綜復(fù)雜的事物應(yīng)該盡可能被隱藏起來 — 但是還是值得在基本層面了解它是如何工作的,以及所涉及的各種挑戰(zhàn)。

在最簡(jiǎn)單的情形下,每一個(gè)設(shè)備將它的 CRUD 修改保存到事務(wù)日志文件中,然后將它們上傳到云端。每一個(gè)修改都包括一個(gè)有序參數(shù),比如一個(gè)時(shí)間戳,然后當(dāng)設(shè)備從其他設(shè)備接收到新的更改時(shí),作為回應(yīng),它會(huì)建立一個(gè)數(shù)據(jù)存儲(chǔ)的本地拷貝。

如果每一個(gè)設(shè)備一直寫事務(wù)日志,云端的數(shù)據(jù)會(huì) 無限制地 增長。重定基準(zhǔn)技術(shù)可以用來壓縮舊的變化集然后設(shè)置一個(gè)新的 基準(zhǔn)線 。實(shí)際上,由所有舊變化的結(jié)束到新對(duì)象的產(chǎn)生代表了存儲(chǔ)的初始化狀態(tài)。這減少了歷史遺留的冗余的日志。比如,如果刪除了一個(gè)對(duì)象,所有與這個(gè)對(duì)象相關(guān)的修改都被刪除了。

A-P2P 是復(fù)雜的

這一段簡(jiǎn)短的描述也許使 A-P2P 看起來是簡(jiǎn)單的算法,但是上面的描述隱藏了許多許多復(fù)雜的東西。A-P2P 是復(fù)雜的,甚至比其他數(shù)據(jù)同步的形式都要復(fù)雜

A-P2P 最大的一個(gè)風(fēng)險(xiǎn)是發(fā)散 (divergence)。由于沒有中央服務(wù)器,沒有不同設(shè)備間的直接通訊,隨著時(shí)間的推移,一個(gè)不良的實(shí)現(xiàn)很容易導(dǎo)致不一致性。(我敢打賭,作為一個(gè)應(yīng)用程序開發(fā)者,你絕對(duì)不想處理像蝴蝶效應(yīng)那樣的問題。)

如果你能保證在云端永久存儲(chǔ)著全部數(shù)據(jù)存儲(chǔ)的最新副本,A-P2P 也就沒那么難了。但是,每一次存儲(chǔ)都拷貝數(shù)據(jù)需要大量的數(shù)據(jù)傳輸,所以 A-P2P 的應(yīng)用程序需要以塊為單位接收數(shù)據(jù),而且它們也不能及時(shí)的知道其他數(shù)據(jù)和設(shè)備。修改甚至?xí)话错樞虻竭_(dá),或者期望從其他設(shè)備發(fā)來的修改還沒有來到。你可以從字面上期望看到還沒有被創(chuàng)建的對(duì)象發(fā)生的改變。

不僅僅是變化可能無序到達(dá),甚至決定順序應(yīng)該是怎樣的都是有挑戰(zhàn)性的。時(shí)間戳通常是不可信的,特別是在 iPhone 這樣的客戶端上。如果你不小心,接受了一個(gè)將來時(shí)間的時(shí)間戳,這可能會(huì)使你不能添加新的改變。使用更健壯的方式使事件及時(shí)按序到達(dá)是可行的 (比如,Lamport TimestampsVector Clocks),但是還是有代價(jià)的:那就只能近似的使事件及時(shí)按序地到達(dá)。

類似這樣的細(xì)節(jié)還有很多,他們都給 A-P2P 的實(shí)現(xiàn)帶來了挑戰(zhàn)。但是那不意味著我們不要應(yīng)該嘗試?;貓?bào)—后端未知的同步存儲(chǔ)—是有價(jià)值的目標(biāo),而且能夠降低在應(yīng)用程序中實(shí)現(xiàn)同步的困難。

一個(gè)已解決的問題?

我經(jīng)常聽到人們說同步是一個(gè)已經(jīng)解決了的問題。我多么希望事實(shí)如聽上去那樣簡(jiǎn)單,因?yàn)槟菢拥脑捗恳粋€(gè)應(yīng)用程序都會(huì)支持同步。事實(shí)上,只有很少的應(yīng)用程序支持同步。更準(zhǔn)確來說,同步的方案不易被接納,代價(jià)高,或者在某些方面受限。

我們已經(jīng)知道數(shù)據(jù)同步算法有很多不同的形式,而且確實(shí)沒有普適的方法。你使用的方案取決于你的應(yīng)用程序的需要,你的資源,以及你的編程水平。

你的應(yīng)用是否需要處理大量的媒體數(shù)據(jù)?除非你有大量的啟動(dòng)資金,否則你最好在本地網(wǎng)絡(luò)使用好用的老式的 S-P2P,就像 iTunes 那樣。

想讓單個(gè)數(shù)據(jù)模型擴(kuò)展到社交網(wǎng)絡(luò)或者實(shí)現(xiàn)跨平臺(tái)?自定義 Web 服務(wù)的 S-CS 也許是一個(gè)選擇。

正在開發(fā)一個(gè)新的應(yīng)用程序,重點(diǎn)是要無論在任何地方都能夠同步,但是你又不想花費(fèi)太多的時(shí)間在這方面?那么就使用像 Dropbox Datastore API 這樣的 A-CS 方案吧。

又或者你已經(jīng)有了一個(gè)基于 Core Data 的應(yīng)用程序,不想和服務(wù)器混在一起,而且又不想被某個(gè)供應(yīng)商鎖起來?那么像 Ensembles 這樣的 A-P2P 方案就是你最好的選擇。(好吧,我承認(rèn),我是 Ensembles 項(xiàng)目的創(chuàng)立者和主要程序員。)

總之,做選擇的時(shí)候,要明智一點(diǎn)兒。:)