CloudKit 上手

Baas

對於獨立客户端開發者來説,維護一個服務器成本相當高:你需要學習服務端技能、租用服務器、考慮擴展問題、還得花精力去維護,還有一個微不足道的原因是租服務器要花錢。

幸虧 IT 巨頭們已經幫我們解決了這個問題,把後端能力打包成一個服務,讓開發者不需要操心服務器相關的任何事情,只需要直接調用 API,這就是傳説中的 BaaS(Backend as a Service)。

典型的 BaaS 包含下面的功能:

  • 數據存儲
  • Crash 統計
  • Analytics
  • 遠程配置
  • 推送

強大如 Firebase 還有其他許多功能:

  • Dynamic Link(跨平台的 Universal Link)
  • AdMob 廣告平台
  • Web 託管

實際上,如果你的 app 體量不大並且功能簡單,可以不花錢享受上面的所有服務。但弊端是一旦體量大了,需要更多的服務端開發需求時,BaaS 就很難滿足了。

平台選擇

市面上已經有很多 BaaS 平台可選:

  • Google 的 Firebase:功能全面且強大,但由於是 Google 的服務,被 GFW 照顧得很好。實測 Analytics 和 AdMob 功能可用(後台需要翻牆),數據庫功能和動態鏈接功能被牆。
  • LeanCloud:有存儲、消息、分析功能,算國內名氣比較大的 BaaS 提供商。
  • WildDog:主要致力於通信領域,瞭解不多。
  • CloudKit:蘋果親兒子,主要提供的是數據存儲功能,可以在 iOS/macOS 和 Web 端訪問。

選擇 CloudKit 的原因一般有幾個:

  • Apple 自家的服務,基本不用擔心服務穩定性和公司哪天突然倒閉的問題。
  • 和 Apple ID 打通,如果不想搭建自己的賬號系統,可以不用關心賬户體系的問題。
  • Apple 和某組織關係處理得比較好,不會被照顧。

缺點也很明顯:不支持安卓。

功能

CloudKit 的主要功能是存儲數據(CURD)和監聽數據變化,後者可以方便地實現多端(Apple 全家桶)的數據同步。

基本概念

CloudKit 上手
CloudKit 上手

上面這張圖出自 WWDC 2017 的 keynote,很好地展示了 CloudKit 中的核心概念。

  • Apple 提供了兩套數據庫環境:Development 和 Production,兩個環境功能相同但數據是隔離的,方便開發和測試。
  • 每個數據環境中包含三個數據庫:
    • Public Database:任何人可讀寫。
    • Shared Database:可以用來實現用户間的數據共享,比如便籤的共享。
    • Private Database:每個用户只能訪問自己的數據,開發者無法訪問。
  • 數據庫內部可以包含多個 Zone,一般使用默認的 Zone 就足夠了。
  • 每個 Zone 中包含若干的 Record,可以理解成數據中的一行,每條 Record 都有自己的 RecordType,用來描述每個字段的名稱和類型。
  • Reference:Record 中的字段可以引用其他的 Record 來表達關係。
  • 下面有一張術語對照表:

    RDBMS LeanCloud CloudKit
    Database Application Database
    Table Class Zone
    Row Object Record
    Index Index Index
    JOIN Reference Reference

    使用

    瞭解了上面的概念後就可以開始使用了。首先需要在 Xcode 中開啟 iCloud 中的 CloudKit 功能。

    存儲數據

    存儲數據過程非常簡單:獲取一個 Public Database 的實例,創建一個 CKRecord,調用 saveRecord 方法即可。因為是網絡調用,因此要做好錯誤處理。

    let publicDB = CKContainer.default().publicCloudDatabase
        
    let greatID = CKRecordID(recordName: "GreatPlace")
    let place = CKRecord(recordType: "Place", recordID: greatID)
        
    publicDB.save(place) { savedRecord, error in
        // handle errors here
    }
    

    查詢數據

    我們有兩種方式查詢數據:

    • 通過 CKRecordID 獲取一條數據
    let recordID = CKRecordID(recordName: "GreatPlace")
    
    publicDB.fetch(withRecordID: recordID) { (fetchedPlace, error) in
        guard let fetchedPlace = fetchedPlace else {
            // handle errors here
            return
        }
    
        let name = fetchedPlace["name"] as? String ?? "Unnamed Place"
        fetchedPlace["name"] = name + " Door A" as CKRecordValue
    }
    
    • 通過 CKQuery 查詢滿足條件的多條數據
    let predicate = NSPredicate(format: "name BEGINSWITH 'Apple Store'")
    let query = CKQuery(recordType: "Place", predicate: predicate)
    
    publicDB.perform(query, inZoneWith: nil) { (results, error) in
        // ...
    }
    

    修改數據

    查詢數據,修改,然後保存。

    刪除數據

    過程跟 fetch 類似:

    let recordID = CKRecordID(recordName: "GreatPlace")
    
    publicDB.fetch(withRecordID: recordID) { (recordID, error) in
     // handle errors here
    }
    

    訂閲

    我們可以通過 CKRecordZoneSubscription 或者 CKQuerySubscription 來訂閲數據的變化,這樣當數據發生變化時設備會收到推送。

    let predicate = NSPredicate(format: "description CONTAINS 'party'")
        
    let subscription = CKSubscription(recordType: "Checkin", predicate: predicate, options: .firesOnRecordCreation)
        
    let info = CKNotificationInfo()
    info.alertLocalizationKey = "NEW_PARTY_ALERT_KEY"
    info.soundName = "NewAlert.aiff"
    info.shouldBadge = true
        
    subscription.notificationInfo = info
        
    publicDB.save(subscription) { subscription, error in
        //...
    }
    

    Apple 寫了一篇詳細的 文檔 來演示如何在本地緩存 CloudKit 的數據。

    後台

    Apple 還提供了一個 Dashboard ,可以很方便地進行數據的管理。

    參考