滾蛋吧!服務(wù)器 · Begining CloudKit

轉(zhuǎn)載請(qǐng)注明,原文地址:滾蛋吧!服務(wù)器 · Begining CloudKit

各位早年大概都聽說過Parse這家領(lǐng)先的BaaS提供商,它為移動(dòng)開發(fā)提供強(qiáng)有力的后端支持,包括云存儲(chǔ)、數(shù)據(jù)分析、用戶關(guān)系等等。不過它的命運(yùn)大概也就是被FB收購之后被家暴中了李陽神功第九重,以至于一年之后暴斃家中。

什么?你沒聽說過Parse?沒聽說過BaaS?那LeanCloud呢?都不知道?好吧,不送了您呢。

今天的豬腳CloudKit,作為Apple在iOS8上推出的基于iCloud的一個(gè)云端數(shù)據(jù)存儲(chǔ)服務(wù),提供了低成本的云存儲(chǔ)并能作為一個(gè)后端服務(wù),通過用戶們的iCloud賬號(hào)分享其應(yīng)用數(shù)據(jù)。以上是行話,CloudKit對(duì)于移動(dòng)開發(fā)者好處請(qǐng)自行QA or Here。

至于為啥三年后的今天才蹭這個(gè)熱點(diǎn),還是歸咎于今年正式出道,成了流落街頭的個(gè)人開發(fā)夠。


我能怎么辦?我也很絕望?。。?!

你要問我原因???


iOS沒人要辣

又或者。。。


打工這方面 打工是不可能打工的 這輩子不可能打工的

本文你將學(xué)習(xí)到CloudKit框架的所有方面,包括使用CloudKit Dashboard管理數(shù)據(jù)庫以及創(chuàng)建和修改記錄等重要基礎(chǔ)知識(shí),還有更高級(jí)的功能,如管理數(shù)據(jù)沖突,共享數(shù)據(jù)等。
但有一個(gè)最大最大的問題,你需要一個(gè)真實(shí)的并且沒有過期的開發(fā)者賬戶,而不是去買個(gè)證書就能搞定的。如果你是一個(gè)真正的iOS開發(fā)者,我相信你即便沒有自己的開發(fā)賬戶,也有公司的。如果沒有那還是趕緊打住,不要繼續(xù)浪費(fèi)生命了。

社會(huì)你拉哥,人狠話不多?。?!

在此CloudKit教程中,我們將通過創(chuàng)建一個(gè)名為BabiFüd的餐廳評(píng)級(jí)App,以此來實(shí)際操作CloudKit。

注意:此CloudKit教程中的Demo,需要一個(gè)iOS開發(fā)者帳戶。否則將無法啟用iCloud授權(quán)或訪問CloudKit dashboard。

本教程的Demo,BabiFüd是一個(gè)類似于“速度餐廳”的App。用戶根據(jù)小屁孩友好度,而不是根據(jù)食品質(zhì)量,服務(wù)速度或價(jià)格來評(píng)價(jià)的餐廳。 這里面包括設(shè)施新舊,小屁孩餐具和食品的健康程度來作為評(píng)價(jià)基準(zhǔn)。
該應(yīng)用程序包含四個(gè)選項(xiàng)卡:附近餐廳列表,附近餐館的地圖,用戶筆記和設(shè)置。本教程中我們只使用附近餐館的列表這個(gè)選項(xiàng)卡。下面簡(jiǎn)單的展示下Demo效果。

模型類通過調(diào)用CloudKit來支撐視圖。records作為CloudKit對(duì)象。Establishment是在模型中的主要record類型,它代表Demo中的各種餐館。

不逼逼了,開擼

我們先下載初始工程

在開始正式編碼之前,必須更改工程的Bundle IDTeam,就如前面說的,必須要有付費(fèi)的開發(fā)者計(jì)劃才能獲取到CloudKit權(quán)限。熟悉iOS開發(fā)的童鞋對(duì)這個(gè)過程肯定是So easy。

打開BabiFud.xcodeproj,并在Project Navigator選擇BabiFud工程,接著選擇BabiFud target,在General選項(xiàng)里替換好Bundle Identifier,最后選著好有付費(fèi)開發(fā)者計(jì)劃的Team即可。

得益于新版Xcode的優(yōu)勢(shì),Team將自動(dòng)綁定好Bundle Identifier,現(xiàn)在,你只需要設(shè)置好CloudKit并且創(chuàng)建一些containers來保存數(shù)據(jù)即可。

Entitlements 和 Containers

在添加任何數(shù)據(jù)之前,我們需要一個(gè)Container也就是官方術(shù)語中的容器來保存數(shù)據(jù)記錄,也就是RecordContainer在官方術(shù)語中是服務(wù)器上所有應(yīng)用程序數(shù)據(jù)概念位置。目前有三種,Public,PrivateShare

  • Public:公有數(shù)據(jù),同一個(gè)App中所有用戶都能訪問的數(shù)據(jù)存儲(chǔ)區(qū)域。
  • Private:用戶的隱私數(shù)據(jù),只有用戶iCloud賬戶授權(quán)的設(shè)備才能訪問。
  • Share:可分享的數(shù)據(jù),用于用戶之間數(shù)據(jù)分享。

要?jiǎng)?chuàng)建容器,首先需要啟用iCloud授權(quán)。如圖在target editor選擇Capabilities選項(xiàng)卡。然后將iCloud權(quán)限開關(guān)打開。
此時(shí),Xcode可能會(huì)提示需要一個(gè)已激活開發(fā)者計(jì)劃的iOS開發(fā)者帳戶來登錄。
最后,如圖所示啟用CloudKit
這將創(chuàng)建一個(gè)名為iCloud.<your app's bundle id>的容器,如圖所示:

iCloud問題排查

如果在創(chuàng)建,構(gòu)建項(xiàng)目或運(yùn)行應(yīng)用程序時(shí)看到任何警告或錯(cuò)誤,或者Xcode正在吐槽Container ID有問題什么的,可以根據(jù)以下提示進(jìn)行故障排除:

  • 如果上述步驟操作iCloud Kit顯示任何警告或錯(cuò)誤,請(qǐng)嘗試Fix Issue按鈕,Xcode并沒有你想象中的那么人工智能,或者需要修復(fù)幾次。

  • 為避免Container IDBundle ID沖突。如,Bundle IDcom.<your domain> .BabiFud,則iCloud里的Container IDiCloud.com.<your domain> .BabiFud。這個(gè)工作Xcode會(huì)自動(dòng)幫你完成,務(wù)須擔(dān)心!

  • 由于CloudKit要訪問數(shù)據(jù)的全局標(biāo)識(shí)符,所以Container ID必須唯一(其實(shí)Container ID包含Bundle ID,App要上架Bundle ID肯定要唯一,所以也就沒什么好說明的了)。

  • 如果能確保自己的Apple ID是在開發(fā)者計(jì)劃的有效期內(nèi),只需要在配置項(xiàng)里選好對(duì)應(yīng)的TeamXcode就會(huì)自動(dòng)幫你完成證書配置文件的一系列工作,如果偶爾抽風(fēng)了,可以強(qiáng)退,也闊以直接編輯info.plist或者BabiFud.entitlements。

CloudKit Dashboard

完成必要的設(shè)置之后,下一步就要?jiǎng)?chuàng)建記錄類型(Rcord Types)和定義數(shù)據(jù)了。我們可以直接點(diǎn)擊CloudKit儀表盤,如圖上位置。

你也可以直接訪問地址:https://icloud.developer.apple.com/dashboard/。

新版的界面就長(zhǎng)這樣,看起來比老版本丑了不是一個(gè)數(shù)量級(jí),設(shè)計(jì)組的人怎么想的,賜予你們隨意感受下:


新版CloudKit Dashboard包含:Data,LogsTelemetry,Public Database Usage,Api Access。

  • Data:包含了ZONES,RECORDS,RECORD TYPES,INDEXES,SUBSCRIPTIONS,SUBSCRIPTION TYPES,SECURITY ROLES,CloudKit的數(shù)據(jù)中心入口,本教程暫時(shí)只使用Record Types,其他類型后續(xù)講解。
  • Logs:查看服務(wù)器活動(dòng)日志,顯示數(shù)據(jù)庫操作,推送通知以及對(duì)應(yīng)環(huán)境中的其他活動(dòng)。
  • Telemetry:查看對(duì)應(yīng)環(huán)境中服務(wù)器端性能和數(shù)據(jù)庫利用率的圖表,分享和推送事件。
  • Public Database Usage:查看公共數(shù)據(jù)庫使用情況的圖表,包括活躍用戶,請(qǐng)求頻率,資產(chǎn)轉(zhuǎn)移和數(shù)據(jù)庫存儲(chǔ)。
  • Api Access:管理API令牌和服務(wù)器密鑰,允許對(duì)應(yīng)環(huán)境進(jìn)行Web服務(wù)調(diào)用。

Record Types:它可以定義了很多字段。如果用面向?qū)ο髞斫忉專拖褚粋€(gè)類。一個(gè)記錄可以看做是一份實(shí)例,簡(jiǎn)單理解的話,它其實(shí)就是一個(gè)鍵值對(duì)的數(shù)據(jù)結(jié)構(gòu)集合。

創(chuàng)建Record Type

在這里,搭配我們的Demo需要?jiǎng)?chuàng)建一個(gè)名為EstablishmentRecord Type數(shù)據(jù)模型,企業(yè)模型需要很多數(shù)據(jù)構(gòu)成:名稱,位置和可用性,以及各種適合兒童的選項(xiàng)。除了內(nèi)置字段以外,我們的自定義字段包含:

  • Name:企業(yè)名稱。
  • Location:企業(yè)地理位置信息。
  • CoverPhoto:企業(yè)Logo或者封面。
  • ChangingTable:嬰兒換衣臺(tái)類型。
  • SeatingType:座位類型。
  • HealthyOption:健康指數(shù)選項(xiàng)。
  • KidsMenu:兒童菜單。

CloudKit Dashboard里進(jìn)入DevelopmentData分組,選擇RECORD TYPE欄,如圖所示,選擇Create New Type創(chuàng)建新的記錄類型:

記住新創(chuàng)建的記錄類型名稱為:Establishment,千萬別弄錯(cuò)了,不然Demo報(bào)錯(cuò)找不到對(duì)應(yīng)的記錄。

接下來我們添加自定義字段,點(diǎn)擊Add Field,新建Name字段,類型屬性是String,最后點(diǎn)擊Save Record Type保存新建字段。

然后新建索引,切換到INDEXS欄,選中剛剛新建的記錄類型Establishment,點(diǎn)擊Add IndexName字段添加三個(gè)索引,分別是:QUERYABLE,SOTREABLE,SEARCHABLE

注意,CloudKit Quick Start官方文檔沒有及時(shí)更新,在老版本里面,新建字段會(huì)自動(dòng)新建索引,新版CloudKit Dashboard則不會(huì),需要我們自己按需添加。

剩下的Field字段Index索引按照下表自行添加:

我們可以一次性點(diǎn)擊添加多個(gè)字段,你非要浪費(fèi)生命一個(gè)個(gè)添加我也沒有什么辦法來說你。


添加之后基本上就長(zhǎng)這樣了,如果程序報(bào)錯(cuò),可以回來稍微對(duì)照一盤。



一次性添加字段,一定要檢查好字段名稱和對(duì)應(yīng)的類型屬性。如果你弄錯(cuò)了,唯一能改的方法就是刪了對(duì)應(yīng)字段,再從新添加。

接下來,就要添加真正的記錄了。選中RECORDS欄,確認(rèn)好Public DatabaseDefault Zone,然后點(diǎn)擊Create New Record…按鈕,創(chuàng)建真正的記錄。

接著我們要做到就是添加一些虛擬數(shù)據(jù)。至于位置信息建議都稍微集中點(diǎn),這里我們把定位都設(shè)在蘋果總部附近,方便在模擬器中查看。請(qǐng)根據(jù)下圖把模擬數(shù)據(jù),或者你興致好自己想也成。

創(chuàng)建完成之后,怎么知道有沒有成功呢?得益于我們之前已經(jīng)建立好索引,現(xiàn)在我們直接選擇好記錄類型查詢即可。


新版本UI不像老版本,創(chuàng)建成功之后會(huì)直接顯示記錄,而是需要根據(jù)自己需求查詢。

對(duì)于每個(gè)記錄,數(shù)據(jù)和App里表示可能完全是不同的,例如,SeatingTypeChangingTablestructs。因此,座椅類型的Int值可能對(duì)應(yīng)于“高腳椅”或“助推器”座椅。對(duì)于HealthyOptionKidsMenu,Int值表示布爾類型:0表示建立不具有該選項(xiàng),1表示它是。

如果你一直在跟著教程走,前期已經(jīng)把開發(fā)者賬號(hào)準(zhǔn)備好,并且工程的證書,配置文件,iCloud報(bào)錯(cuò)都搞定之后,我們馬上才能開始真正的代碼之旅。

如果還有問題,可以對(duì)照教程查錯(cuò)或是自行檢查。

你要是操作的夠絲滑,現(xiàn)在可以打開Xcode和我們的Demo工程。是時(shí)候開始代碼狗真正的搬磚工作了!

記錄查詢

CKQuery對(duì)象用于從數(shù)據(jù)庫中查詢記錄。它描述了如何查找符合特定條件的指定記錄類型的所有記錄。它們可以是以M打頭的名稱字段的所有記錄,或是強(qiáng)化座椅的所有記錄,亦或者3km內(nèi)的所有記錄“。那查詢的表達(dá)式當(dāng)然是用NSPredicate。謂詞也用于Core Data,也適用于CloudKit,畢竟NSPredicate在原生開發(fā)里是通用的查詢表達(dá)式。

但不要高興的太早,CloudKit僅支持NSPredicate部分函數(shù)。 包括常用數(shù)學(xué)運(yùn)算和比較,字符串的集合操作(例如”列表中的字段匹配”)和特殊距離函數(shù)。至于distanceToLocation:fromLocation:這種函數(shù)已添加到NSPredicate中,以便CloudKit里的位置記錄與來自已知位置的指定半徑內(nèi)的位置字段進(jìn)行匹配。這種類型的謂詞將在下面做出詳細(xì)介紹。對(duì)于其他類型的查詢,CKQuery類引用包含了詳細(xì)的函數(shù)列表以及如何使用它們的說明。

注意:CloudKit包括對(duì)CLLocation對(duì)象的支持。使用這種Core Location的坐標(biāo)對(duì)象,更方便的創(chuàng)建兩個(gè)坐標(biāo)之間的計(jì)算查詢,避免你寫很多雜亂無章的數(shù)學(xué)表達(dá)式。

好,我們現(xiàn)在點(diǎn)開Model/Model.swift文件,使用下面代碼替換掉fetchEstablishments(_ location:CLLocation, radiusInMeters:CLLocationDistance)方法的內(nèi)容:

func fetchEstablishments(_ location: CLLocation, radiusInMeters: CLLocationDistance) {
  // 1
  let radiusInKilometers = radiusInMeters / 1000.0
  // 2
  let locationPredicate = NSPredicate(format: "distanceToLocation:fromLocation:(%K,%@) < %f", "Location", location, radiusInKilometers)
  // 3
  let query = CKQuery(recordType: EstablishmentType, predicate: locationPredicate)
  // 4
  publicDB.perform(query, inZoneWith: nil) { [unowned self] results, error in
    if let error = error {
      DispatchQueue.main.async {
        self.delegate?.errorUpdating(error as NSError)
        print("Cloud Query Error - Fetch Establishments: \(error)")
      }
      return
    }
    self.items.removeAll(keepingCapacity: true)
    results?.forEach({ (record: CKRecord) in
      self.items.append(Establishment(record: record,
                                      database: self.publicDB))
    })
    DispatchQueue.main.async {
      self.delegate?.modelUpdated()
    }
  }
}

按照編號(hào)代碼功能如下:

  • 1.CloudKit中謂詞功能的距離單位是公里,這行代碼只是距離單位轉(zhuǎn)換。
  • 2.根據(jù)當(dāng)前位置和半徑范圍,篩選出范圍內(nèi)的餐飲企業(yè),過濾掉不需要的對(duì)象。
  • 3.根據(jù)記錄類型和謂詞查詢條件,創(chuàng)建CKQuery對(duì)象用于遠(yuǎn)程查詢。
  • 4.最后執(zhí)行performQuery(_:inZoneWithID:completionHandler:),iCloud將按照查詢條件進(jìn)行數(shù)據(jù)篩選,在閉包里等查詢結(jié)果的返回。

inZoneWithID參數(shù)如果不傳,那就是默認(rèn)的公有數(shù)據(jù)庫的DefaultZone。如果想把公有和私有的數(shù)據(jù)庫都進(jìn)行檢索,就必須分開查詢。

對(duì)于CKDatabase的實(shí)例publicDB,我們可以查看Model.swift頂部:

let container: CKContainer
let publicDB: CKDatabase
let privateDB: CKDatabase
  
init() {
  // 1
  container = CKContainer.defaultContainer() 
  // 2
  publicDB = container.publicCloudDatabase 
  // 3
  privateDB = container.privateCloudDatabase 
}

上述我們定義的集中數(shù)據(jù)庫實(shí)例:

  • 1.默認(rèn)容器就是你在iCloud Dashboard窗口中看到那些內(nèi)容。
  • 2.公共數(shù)據(jù)庫是你應(yīng)用程序所有用戶共享的數(shù)據(jù)庫。
  • 3.私有數(shù)據(jù)庫僅包含屬于當(dāng)前登錄用戶的數(shù)據(jù),此教程暫不討論。

該代碼將從公共數(shù)據(jù)庫檢索一些本地的餐飲企業(yè),但必須將其連接到視圖控制器才能看到對(duì)應(yīng)內(nèi)容。

設(shè)置回調(diào)

這里我們用熟悉的代理模式來處理回調(diào)。在Model.swift頂部實(shí)現(xiàn)如下協(xié)議:

protocol ModelDelegate {
  func errorUpdating(error: NSError)
  func modelUpdated()
}

接著打開MasterViewController.swift,覆蓋掉modelUpdated()的實(shí)現(xiàn):

func modelUpdated() {
  refreshControl?.endRefreshing() 
  tableView.reloadData() 
}

當(dāng)有數(shù)據(jù)回來時(shí),tableView(_:cellForRowAtIndexPath:)已經(jīng)添加好實(shí)現(xiàn),會(huì)自動(dòng)Cell處理刷新。
同樣,覆蓋掉errorUpdating(_:)的實(shí)現(xiàn):

func errorUpdating(_ error: NSError) {
  let alertController = UIAlertController(title: nil,
                                          message: error.localizedDescription,
                                          preferredStyle: .alert)
    
  alertController.addAction(UIAlertAction(title: "Dismiss", style: .default, handler: nil))
    
  present(alertController, animated: true, completion: nil)
}

當(dāng)查詢產(chǎn)生錯(cuò)誤時(shí)調(diào)用此方法。由于網(wǎng)絡(luò)太差或CloudKit的某些特定問題(如缺少,不正確的用戶權(quán)限或查詢中沒有記錄),都可能會(huì)發(fā)生錯(cuò)誤。
對(duì)于任何類型的遠(yuǎn)程服務(wù)屌用時(shí),良好的錯(cuò)誤處理邏輯是至關(guān)重要的?,F(xiàn)在,簡(jiǎn)單處理,只需要向用戶顯示返回錯(cuò)誤的消息即可。

然而,有一種常見問題就是用戶沒有登錄到iCloud或沒有為此應(yīng)用打開iCloud權(quán)限。所以你可以修改errorUpdating(_:)來處理這種常見情況。提示:這兩種錯(cuò)誤碼CKErrorCode返回都為1

考慮到懶癌患者:

func errorUpdating(_ error: NSError) {
  let message: String
  if error.code == 1 {
    message = "Log into iCloud on your device and make sure the iCloud drive is turned on for this app."
  } else {
    message = error.localizedDescription
  }
  let alertController = UIAlertController(title: nil,
                                          message: message,
                                          preferredStyle: .alert)
    
  alertController.addAction(UIAlertAction(title: "Dismiss", style: .default, handler: nil))
    
  present(alertController, animated: true, completion: nil)
}

那么剩下就是讓Xcode飛起來,你就能看到你如下列表。


疑難解答

  • 如果您使用的是iOS模擬器,并且列表不能正常顯示,請(qǐng)通過從Xcode的功能菜單,路徑:Debug\Simulate Location\San Francisco, CA, USA,中進(jìn)行選擇。確保設(shè)置了正確的位置,下拉刷新拉取正確數(shù)據(jù),不要干等著浪費(fèi)生命。
  • 如果您使用的是iPhone或iPad等實(shí)體機(jī)設(shè)備,并且啟用位置服務(wù),要是列表不能顯示,那么肯定是離我們的虛擬餐廳的距離位置還不夠近。
    現(xiàn)在你有兩個(gè)選擇:把我們的模擬數(shù)據(jù)位置改到你當(dāng)前位置的附近,或使用模擬器運(yùn)行應(yīng)用程序。要還不行,我建議牽條狗去蘋果總部遛彎得了。
  • 當(dāng)然你要想顯示的前提是,你真的有數(shù)據(jù),如果按照前面的教程做了之后,CloudKit Dashboard里肯定是有完整數(shù)據(jù)的,前面也說過,如果你要修改數(shù)據(jù),唯一方法,刪了重建。

在調(diào)試CloudKit的時(shí)候可能會(huì)遇到相當(dāng)棘手的錯(cuò)誤,在做本教程的時(shí)候,我并沒有遇到什么蛋疼問題,如果你有遇到,可以使用CKErrorCode的枚舉來定位問題,這樣免得你像個(gè)無頭蒼蠅一樣不知所措。

以下是一些常見錯(cuò)誤:

  • .badContainer:指定的未知容器或未經(jīng)授權(quán)。
  • .notAuthenticated:當(dāng)前用戶未通過授權(quán)驗(yàn)證,并且沒有用戶記錄可用。如果用戶沒有登錄到iCloud,可能會(huì)發(fā)生這種情況。
  • .unknownItem:指定的記錄不存在。

當(dāng)我們?cè)诶〔蛷d數(shù)據(jù)的時(shí)候,只看到餐廳名字服務(wù)內(nèi)容,并沒有看到餐廳圖片,What the fuck?。。?br> 做個(gè)網(wǎng)絡(luò)開發(fā)的都知道,不管你是拉取的圖片是二進(jìn)制數(shù)據(jù)或者是圖片地址,都要自行加載顯示,所以不要精慌,教程繼續(xù)。。。

二進(jìn)制數(shù)據(jù)資源

接下來該整合二進(jìn)制數(shù)據(jù)資源,這里的資源就是我們所需要的圖片,當(dāng)然可以是任何你想要的數(shù)據(jù)資源,都是以二進(jìn)制的方式存在數(shù)據(jù)庫里。這里我們需要把二進(jìn)制的圖片加載到MasterViewController的列表里。
這里我們自己實(shí)現(xiàn)相關(guān)的圖片下載和相關(guān)的加載邏輯。

打開Model/Establishment.swift文件,替換loadCoverPhoto(_:)方法里的代碼:

func loadCoverPhoto(completion:@escaping (_ photo: UIImage?) -> ()) {
  // 1
  DispatchQueue.global(qos: DispatchQoS.QoSClass.background).async {
    var image: UIImage!
    defer {
      completion(image)
    }
      // 2
    guard let asset = self.record["CoverPhoto"] as? CKAsset else {
      return
    }
      
    let imageData: Data
    do {
      imageData = try Data(contentsOf: asset.fileURL)
    } catch {
      return
    }
    image = UIImage(data: imageData)
  }
}

此方法的作用就是圖像延遲加載:

  • 我們?cè)谙螺d資源的同時(shí),也可以查詢其他記錄,基于用戶體驗(yàn)的問題,這里我們使用異步下載的方式,所以把下載代碼放到dispatch_async異步加載的閉包里。
  • 數(shù)據(jù)資源以CKAsset實(shí)例的方式存放在CKRecord里,所以需要我們根據(jù)存在方式自行轉(zhuǎn)換,這里提供的是File URL的方式進(jìn)行本地加載。
  • 使用UIImage的實(shí)例方法加載本地二進(jìn)制圖像數(shù)據(jù)。
  • 當(dāng)加載到圖像之后我們會(huì)進(jìn)行回調(diào),請(qǐng)注意,無論執(zhí)行哪個(gè)回調(diào),此defer block都將被執(zhí)行。例如,如果沒有圖像資源,則圖像在返回時(shí)不會(huì)設(shè)置,餐廳不顯示圖像。

現(xiàn)在再次運(yùn)行App,看下圖像是不是是在列表里已經(jīng)被異步加載了。


關(guān)于CloudKit資源有兩個(gè)問題:

  • 二進(jìn)制資源只能存在于CloudKit屬性為Assets記錄中。它們不能單獨(dú)存在,刪除記錄也將刪除任何關(guān)聯(lián)的Assets資源。
  • 檢索Assets資源可能造成性能影響,因?yàn)槎M(jìn)制資源與其他記錄數(shù)據(jù)是同時(shí)在下載。如果您的應(yīng)用程序大量使用Assets資源,那你就應(yīng)該單獨(dú)新建一個(gè)記錄來存儲(chǔ)這個(gè)Assets資源,并且與對(duì)應(yīng)的記錄數(shù)據(jù)的引用進(jìn)行關(guān)聯(lián)。

結(jié)尾

Demo已經(jīng)可以下載已經(jīng)存在的記錄,并且完整的顯示數(shù)據(jù)信息和圖片。
如果按照教程操作到最后,Demo并不能達(dá)到像我這樣的效果,那我給你提供最終的完整工程,請(qǐng)自行檢查。

最后,你要是我給你幾點(diǎn)建議完善這個(gè)Demo:

  • 用戶可自行添加添加照片,備注,評(píng)論和投訴。
  • 用戶可使用地圖創(chuàng)建新的記錄,Model類中的函數(shù)已經(jīng)有了將記錄保存到公共或私有數(shù)據(jù)庫的示例代碼。
  • 添加過濾和搜索,我們可以通過一個(gè)更復(fù)雜的距離謂詞查詢條件來進(jìn)行精確篩選過濾。CloudKit還支持對(duì)字符串的文本搜索。
  • 提高應(yīng)用程序的性能和數(shù)據(jù)加載體驗(yàn)。CKDatabase是基于NSOperation的實(shí)例,可以使用隊(duì)列的方式來優(yōu)化性能。
  • 提供緩存和數(shù)據(jù)同步,使應(yīng)用程序在離線狀態(tài)下也能照常顯示已經(jīng)緩存數(shù)據(jù)來刷新UI,并重新連接到網(wǎng)絡(luò)的同時(shí)保持內(nèi)容的更新。

使用CloudKit,讓我們可以使用偉大的Apple爸爸提供的后端API來提高用戶體驗(yàn)和縮短開發(fā)流程。如果你對(duì)本教程有任何問題或意見,歡迎參與討論!

入門總體就這些了,深入的進(jìn)階我也在探索當(dāng)中,如果你也想出道,闊以買件竊·格瓦拉T恤穿出去看會(huì)不會(huì)被打死,沒死你就成功出道辣。。。

竊·格瓦拉T恤
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容