Swift +CloudKit開發(fā)入門篇
譯文簡介
CloudKit是蘋果公司推出的基于iCloud的遠(yuǎn)程數(shù)據(jù)存儲服務(wù)。它為存儲和使用用戶的iCloud賬戶的后端存儲服務(wù)共享應(yīng)用數(shù)據(jù)提供了一種低成本的選擇方案。
總體來看,CloudKit主要提供了兩個組件:
- 一個網(wǎng)絡(luò)中心,用于管理記錄類型和任何公共數(shù)據(jù)。
- 一組API,用于在iCloud和設(shè)備之間傳輸數(shù)據(jù)。
CloudKitr的安全性是很高的。用戶的私有數(shù)據(jù)受到完全保護(hù),因為開發(fā)人員只能訪問他們自己的私人數(shù)據(jù)庫而不能查看任何其他用戶的私人數(shù)據(jù)。
對于只運行于iOS平臺的使用大量數(shù)據(jù)但不需要服務(wù)器端大量邏輯的應(yīng)用程序來說,CloudKit是一個不錯的選擇。此外,CloudKit也可用于網(wǎng)絡(luò)和服務(wù)器應(yīng)用程序。
在這個CloudKit教程中,您將獲得使用CloudKit的切身體驗,即你需要創(chuàng)建一個名為BabiFüd的餐廳評級應(yīng)用程序。
為何選擇CloudKit?
你可能想知道,為什么要選擇基于核心數(shù)據(jù)(Core Data)基礎(chǔ)之上的CloudKit,而不是其他BaaS(后端即服務(wù))產(chǎn)品,甚至是基于你自己的服務(wù)器?
原因有三:簡單性,高信譽度和低成本。
簡單性
不像其他的后端解決方案,CloudKit僅需要很少的設(shè)置。你不必選擇、配置或安裝服務(wù)器。此外,安全性和伸縮性也都由蘋果公司來處理。
只需在蘋果官方網(wǎng)站注冊成為iOS開發(fā)者項目成員,您就擁有了使用CloudKit的資格。你不必注冊額外的服務(wù)或創(chuàng)建新帳戶。當(dāng)您在自己的應(yīng)用程序中啟用CloudKit支持時,所有必要的服務(wù)器設(shè)置都將魔術(shù)般自動發(fā)生。
你不需要下載額外的庫并對它們進(jìn)行配置。CloudKit就像任何其他iOS框架一樣導(dǎo)入。CloudKit框架本身通過提供一些針對常見操作的便利的API實現(xiàn)了一定程度的簡單性。
這也方便了用戶使用。由于在設(shè)備設(shè)置(甚至是設(shè)置結(jié)束進(jìn)入應(yīng)用程序時)時CloudKit使用的是輸入的iCloud憑據(jù),所以沒有必要建立復(fù)雜的登錄屏幕。只要用戶登錄,他們就可以無縫地開始使用你的應(yīng)用程序。
高信譽度
CloudKit的另一個好處是,通過依靠蘋果公司而不是應(yīng)用程序開發(fā)人員,用戶可以相信他們的數(shù)據(jù)的隱私性和安全性。CloudKit能夠把您(開發(fā)人員)與用戶數(shù)據(jù)隔離開來。
雖然在調(diào)試程序時無法訪問可能令人沮喪,但另一個方面這也帶來一定好處,因為你不必?fù)?dān)心安全或說服用戶其數(shù)據(jù)的安全性。如果一個應(yīng)用程序用戶信任iCloud,那么他們也可以信任作為開發(fā)人員的你。
低成本
***,對于任何開發(fā)者來說,運行服務(wù)的成本也是一個巨大的投資。即使是***的服務(wù)器主機(jī)也不能為小型、免費或廉價的應(yīng)用程序提供低成本的解決方案。所以總是會有與運行應(yīng)用程序相關(guān)的成本問題。
借助于CloudKit,你可以實現(xiàn)針對免費的公共數(shù)據(jù)的適量的存儲和數(shù)據(jù)傳輸。在WWDC 2015視頻的CloudKit新增功能(https://developer.apple.com/videos/play/wwdc2015/704/)中提供了非常詳盡的收費解釋。
上述所有這些優(yōu)勢,使得CloudKit服務(wù)成為Mac和iOS應(yīng)用程序開發(fā)中更值得選擇的解決方案。
BabiFüd項目功能介紹
本教程中提供的BabiFüd示例應(yīng)用程序使用時下最標(biāo)準(zhǔn)的“速度餐廳”型應(yīng)用程序風(fēng)格。不是沿用傳統(tǒng)式的基于食品質(zhì)量、服務(wù)速度以及價格等評價標(biāo)準(zhǔn),而是使用新型的兒童友好性進(jìn)行評價。這包括設(shè)施更換、加高座椅和健康性食品選擇等可用性標(biāo)準(zhǔn)。
應(yīng)用程序包含四個選項卡:一個附近的餐館列表;一個附近餐館地圖展示;用戶生成注釋和功能設(shè)置。附近的餐館列表選項卡是您將在本教程中使用的唯一部分。當(dāng)然,你現(xiàn)在就可以一瞥運行中的這個示例應(yīng)用程序。
開發(fā)過程中,我使用了一個模型類來支持這些視圖,并封裝對CloudKit的調(diào)用。其中,CloudKit對象稱為記錄(Record)。模型中主要的記錄類型是一個Establishment,它代表了你的應(yīng)用程序中不同的餐館。
開始
首先,請下載本教程中的啟動項目,地址是https://cdn2.raywenderlich.com/wp-content/uploads/2016/06/BabiFud-Cloudkit-Starter.zip。
你必須改變你的應(yīng)用程序的資源標(biāo)識符和團(tuán)隊類型,然后才能開始編碼。為了從蘋果公司獲得必要的授權(quán),您需要設(shè)置團(tuán)隊。擁有一個獨特的資源標(biāo)識符可以使得很多的事更容易操作。
現(xiàn)在,請使用Xcode打開工程BabiFud.xcodeproj。然后,從「Project Navigator」下選擇BabiFud項目,然后選擇「BabiFud target」。接下來,選擇「General」選項卡,使用一些獨特的字符串內(nèi)容更換資源標(biāo)識符(Bundle Identifier)。標(biāo)準(zhǔn)的做法是,使用反向域名符號并包括項目名稱。然后,選擇合適的團(tuán)隊(Team):
現(xiàn)在,你需要在你的應(yīng)用程序中設(shè)置CloudKit支持,并創(chuàng)建一些容器來保存數(shù)據(jù)。
權(quán)限和容器
在向應(yīng)用程序中添加任何數(shù)據(jù)之前,你需要一個容器來保存應(yīng)用程序的記錄。容器,其實僅是一個概念上的位置術(shù)語,對應(yīng)于所有應(yīng)用程序在服務(wù)器上的數(shù)據(jù)。它分為公共和私有數(shù)據(jù)庫兩個組。
要創(chuàng)建一個容器,你首先需要擁有啟用您的應(yīng)用程序的iCloud權(quán)限?,F(xiàn)在,請從目標(biāo)編輯器選擇【Capabilities】選項卡。然后,把iCloud部分中的開關(guān)切換為ON。
現(xiàn)在,Xcode可能會提示您輸入與您的iOS開發(fā)者帳戶相關(guān)聯(lián)的蘋果ID。如果是這樣,那么根據(jù)要求輸入即可。***,通過勾選【Services】組中的CloudKit復(fù)選框來啟用CloudKit。
這將創(chuàng)建一個名為iCloud.<your app’s bundle id>的默認(rèn)容器,如下圖所示:
克服Xcode中iCloud安裝錯誤
如果你在創(chuàng)建權(quán)限、構(gòu)建項目或運行應(yīng)用程序時看到任何警告或錯誤,并注意到Xcode抱怨容器ID;那么,下面提供一些故障排除提示,供您參考:
- 應(yīng)用程序的包ID和iCloud的容器要相匹配并存在于開發(fā)人員帳戶中,這一點是很重要的。例如,如果包標(biāo)識為“com.<your domain>.BabiFud”,那么,iCloud的容器名稱應(yīng)是“iCloud.”,再加上資源包ID“iCloud.com.<your domain>.BabiFud”。
- iCloud的容器名稱必須是唯一的,因為這是使用CloudKit訪問數(shù)據(jù)的全球標(biāo)識符。由于iCloud的容器名稱包含了資源ID,所以該資源ID也必須是唯一的(這就是為什么它必須由com.raywendrelich.BabiFud進(jìn)行修改的原因)。
- 為了過權(quán)限這一關(guān),應(yīng)用程序/包ID顯示于【Certificates】,【Identifiers】和【Profiles】的App ID部分。這意味著,用于簽名應(yīng)用程序的證書必須來自于設(shè)置的團(tuán)隊ID并且必須列出應(yīng)用程序ID;這也就是iCloud的容器id。通常情況下,如果你登錄了一個有效的開發(fā)帳戶,Xcode能夠自動地完成這一切。不幸的是,這有時會導(dǎo)致不同步情況。你可以通過一個新的ID刷新來重新開始,并使用iCloud的功能窗格更改CloudKit容器ID以便進(jìn)行匹配。否則,要解決這個問題,你可能要編輯info.plist文件或BabiFud.entitlements文件,以確保ID值反映你為應(yīng)用程序設(shè)置的包ID。
CloudKit控制面板簡介
在創(chuàng)建完工程所必需的餐館數(shù)據(jù)之后,下一步就是創(chuàng)建一些記錄類型來定義您的應(yīng)用程序所使用的數(shù)據(jù)。您可以使用CloudKit控制面板來實現(xiàn)這一點。從工程的【Capabilities】窗格中點擊【CloudKit Dashboard】,如圖所示。
【注意】你還可以通過在瀏覽器中打開網(wǎng)址https://icloud.developer.apple.com/dashboard/ 來啟動CloudKit控制面板。
這個控制面板是什么樣子呢?請觀察一下這個圖形:
注意到,該控制面板由四部分組成:架構(gòu)(Schema),公共數(shù)據(jù)(Public Data),私有數(shù)據(jù)(Private Data)和管理員(Admin)。
其中,Schema部分代表CloudKit容器中的***層次對象:記錄類型(Record Types),安全角色(Security Roles)及訂閱類型(Subscription Types)。在本教程中,你只要關(guān)心記錄類型即可。
記錄類型(Record Types),是一組定義了單個記錄的字段。對于面向?qū)ο缶幊潭?,一個記錄類型就像一個類。一個記錄可以被認(rèn)為是一個特殊的記錄類型的實例。它代表了容器中的結(jié)構(gòu)化數(shù)據(jù),就像數(shù)據(jù)庫中的一個典型的行,它封裝了一系列鍵/值對。
公共數(shù)據(jù)(PUBLIC DATA)和私有數(shù)據(jù)(PRIVATE DATA)部分,可以讓您在您能夠訪問的數(shù)據(jù)庫中添加數(shù)據(jù)或搜索數(shù)據(jù)。請記住,作為一名開發(fā)人員你可以訪問所有的公共數(shù)據(jù),但只能訪問你自己的私有數(shù)據(jù)。其中,「User Records」存儲關(guān)于當(dāng)前iCloud用戶的數(shù)據(jù),如姓名和電子郵件等?!赣涗泤^(qū)域」(Record Zone)(這里使用的是默認(rèn)的區(qū)域),用于提供一個邏輯組織到一個私有數(shù)據(jù)庫;實現(xiàn)方法是對記錄進(jìn)行分組。注意,自定義區(qū)域支持原子事務(wù),即允許在處理其它操作之前把多個記錄同時保存。不過,有關(guān)自定義區(qū)域的探討已經(jīng)超出本教程的范圍。
管理員(ADMIN)部分,能夠針對您的團(tuán)隊成員提供不同的權(quán)限配置控制。如果你有多個開發(fā)團(tuán)隊成員,你可以在這里限制他們編輯數(shù)據(jù)的能力。當(dāng)然,這也超出本教程范圍。
添加餐館記錄類型
現(xiàn)在,請略微想一想你的應(yīng)用程序的設(shè)計吧。你要跟蹤的每一家餐館都對應(yīng)大量的數(shù)據(jù):名稱、位置以及各種兒童友好的設(shè)施的可用性,等等。記錄類型使用字段來定義每個記錄包含的各個部分中的數(shù)據(jù)。
選擇記錄類型(Record Types)后,單擊詳細(xì)信息窗格左上方的+圖標(biāo)添加一個新的記錄類型,如圖所示。
命名你剛剛創(chuàng)建的新記錄類型為「Establishment」。
你會看到出現(xiàn)一行字段,其中定義了字段名、字段類型和索引等,如下圖所示。注意,有一個字段使用了默認(rèn)名稱「StringField」,這是系統(tǒng)自動為您創(chuàng)建的。
接下來,你要使用新名字「Name」替換「StringField」。字段類型和索引默認(rèn)已匹配您所需要的***個字段的定義,但接下來,你需要對于其他一些字段改變字段類型和索引。單擊【Add Field…】并根據(jù)需要增加新的字段即可。***,你需要添加以下字段:
當(dāng)你添加完所有字段后,你的字段列表應(yīng)該是這樣的:
點擊頁面底部【Save】按鈕保存您的新的記錄類型。
現(xiàn)在,您已經(jīng)準(zhǔn)備好向您的數(shù)據(jù)庫中添加一些示例記錄了。
選擇左側(cè)導(dǎo)航窗格中【PUBLIC DATA】下部的【Default Zone】。該區(qū)域?qū)膽?yīng)用程序的所有公共記錄。如果還沒有選定,那么請從中心窗格的下拉列表中選擇「Establishment」記錄類型。然后單擊右側(cè)詳細(xì)信息窗格中的+圖標(biāo)或【New Record】按鈕,如下圖所示:
這將創(chuàng)建一個新的空的Establishment記錄。
此時,您已經(jīng)準(zhǔn)備好為您的應(yīng)用程序輸入一些測試數(shù)據(jù)了。
需要說明的是,下面的示例數(shù)據(jù)都是虛構(gòu)的。這些餐館數(shù)據(jù)都位于蘋果總部附近,這樣它們可以很容易地出現(xiàn)在模擬器上。
現(xiàn)在,請輸入如下表所述的每個記錄:
【注意】每個CoverPhoto元素對應(yīng)的圖像文件都包含在Xcode項目的「Supporting Files\Sample Images」文件夾中。要將圖像添加到Establishment記錄中,只需將其拖動到CoverPhoto字段中即可。
一旦保存完所有三個記錄,控制面板應(yīng)該是這樣的:
對于每個記錄,輸入的值都代表了數(shù)據(jù)的數(shù)據(jù)庫描述部分。在應(yīng)用程序中,數(shù)據(jù)類型是不同的。例如,SeatingType和ChangingTable都是結(jié)構(gòu)類型的。所以,對于SeatingType字段指定的int值可能對應(yīng)于“high chair”或“booster”這樣的座位。對于HealthyOption和KidsMenu這兩個字段指定的int值表示布爾類型:其中,0是指沒有這一項,1則指有這一項。
***,運行應(yīng)用程序需要你有一個可以用于開發(fā)的iCloud帳戶。請參考蘋果官方文檔https://developer.apple.com/library/tvos/documentation/DataManagement/Conceptual/CloudKitQuickStart/EnablingiCloudandConfiguringCloudKit/EnablingiCloudandConfiguringCloudKit.html#//apple_ref/doc/uid/TP40014987-CH2-SW7。
另外,您還需要在iPhone模擬器中輸入與此帳戶相關(guān)聯(lián)的icloud憑據(jù)。請參考蘋果官方文檔https://developer.apple.com/library/tvos/documentation/DataManagement/Conceptual/CloudKitQuickStart/CreatingaSchemabySavingRecords/CreatingaSchemabySavingRecords.html#//apple_ref/doc/uid/TP40014987-CH3-SW12。
現(xiàn)在,切換回Xcode中。從下一節(jié)開始,你要把上面創(chuàng)建的數(shù)據(jù)集成到您的應(yīng)用程序中!
查詢餐館記錄
CKQuery對象用于從數(shù)據(jù)庫中選擇記錄。CKQuery描述了如何找到符合特定條件的特定類型的所有記錄。這些條件可以是這樣的:所有記錄都有一個以N開頭的Name字段;所有記錄都帶有兒童增高座椅;所有記錄都要滿足在3公里以內(nèi)。這些類型的表達(dá)式都通過NSPredicate對象編碼于Cocoa庫中。NSPredicate能夠評估對象,看它們是否符合指定條件。NSPredicate也用在核心數(shù)據(jù)(Core Data)中,并且自然地融入CloudKit中,因為謂詞通常被定義用于針對某個字段的比較方面。
事實上,CloudKit僅支持NSPredicate功能的一個子集。這些功能包括:數(shù)學(xué)比較,字符串和集合操作(例如“字段匹配列表中的項目之一”),還提供了一個特殊的距離函數(shù)。函數(shù)distanceToLocation:fromLocation:被專門添加到NSPredicate對象定義中,特別支持CloudKit以匹配帶有位置字段的記錄——此已知位置位于指定半徑的范圍內(nèi)。接下來的內(nèi)容中將詳細(xì)介紹這種類型謂詞的用法。對于其他類型的查詢中,CKQuery類參考文檔(https://developer.apple.com/library/ios/documentation/CloudKit/Reference/CKQuery_class/)中包含了有關(guān)其支持的功能及如何使用的詳細(xì)描述。
【注意】CloudKit包括了對CLLocation對象的支持。有一些核心定位框架對象(Core Location Framework)包含了有關(guān)地理坐標(biāo)的信息。這使得開發(fā)人員可以很容易創(chuàng)建一個查詢來尋找指定地理區(qū)域內(nèi)的餐館——而不需要我們自己進(jìn)行所有繁瑣的坐標(biāo)運算。
接下來,在Xcode中打開文件Model/ Model.swift。該文件中包含了所有您的應(yīng)用程序進(jìn)行服務(wù)器調(diào)用的存根。
現(xiàn)在,請使用下面的內(nèi)容來更換fetchEstablishments(_:radiusInMeters:)方法:
- 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.performQuery(query, inZoneWithID: nil) { [unowned self] results, error in
- if let errorerror = error {
- dispatch_async(dispatch_get_main_queue()) {
- self.delegate?.errorUpdating(error)
- print("Cloud Query Error - Fetch Establishments: \(error)")
- }
- return
- }
- self.items.removeAll(keepCapacity: true)
- results?.forEach({ (record: CKRecord) in
- self.items.append(Establishment(record: record,
- database: self.publicDB))
- })
- dispatch_async(dispatch_get_main_queue()) {
- self.delegate?.modelUpdated()
- }
- }
- }
現(xiàn)在,我們按編號來分析一下上面代碼的功能:
1. CloudKit在其距離謂詞中利用公里為計算單位。這一行簡單地把radiusInMeters轉(zhuǎn)換為公里。
2. 根據(jù)從當(dāng)前位置到他們的位置的距離謂詞對餐館進(jìn)行篩選。這個語句使用從用戶的當(dāng)前位置到指定距離內(nèi)的位置值來查找所有餐館。
3. 使用謂詞和記錄類型創(chuàng)建CKQuery對象。執(zhí)行查詢時兩者都將被使用。
4. ***,方法performQuery(_:inZoneWithID:completionHandler :)負(fù)責(zé)發(fā)送查詢到iCloud中,并等待任何匹配的結(jié)果。通過傳遞nil作為inZoneWithID參數(shù)值,可以針對你所在的默認(rèn)區(qū)域進(jìn)行查詢;也就是說,針對你的公共數(shù)據(jù)庫。如果你既想從公共數(shù)據(jù)庫也想從私有數(shù)據(jù)庫中檢索記錄,那么,你必須使用一個單獨的調(diào)用來查詢每個數(shù)據(jù)庫。
你可能想知道:CKDatabase的實例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ù)庫:
1. 默認(rèn)容器是指您在iCloud的功能窗格中指定的那個。
2. 公共數(shù)據(jù)庫是指在你的應(yīng)用程序的所有用戶中共享的那個。
3. 私有數(shù)據(jù)庫只包含屬于當(dāng)前登錄的用戶(在本實例中即指你)的數(shù)據(jù)。
總之,此代碼將從公共數(shù)據(jù)庫中檢索一些地方餐館,但為了在任何應(yīng)用程序中看到相應(yīng)的數(shù)據(jù),必須把它關(guān)聯(lián)到一個視圖控制器。
創(chuàng)建需求回調(diào)函數(shù)
你可以借助熟悉的委托模式來管理通知的問題。下面這個協(xié)議位于Model.swift文件的頂部;當(dāng)然,你需要在你的視圖控制器中實現(xiàn)這個協(xié)議:
- protocol ModelDelegate {
- func errorUpdating(error: NSError)
- func modelUpdated()
- }
- 現(xiàn)在,打開文件MasterViewController.swift,并用以下內(nèi)容替換modelUpdated()方法原有內(nèi)容:
- func modelUpdated() {
- refreshControl?.endRefreshing()
- tableView.reloadData()
- }
當(dāng)新數(shù)據(jù)可用時此方法會被調(diào)用。在方法tableView(_:cellForRowAtIndexPath:)中實現(xiàn)了所有關(guān)于表格視圖單元格與CloudKit對象綁定的代碼。您可以自行分析學(xué)習(xí),恕在此不再贅述。
接下來,在文件MasterViewController.swift中,請使用如下內(nèi)容更換errorUpdating(_ :)方法:
- func errorUpdating(error: NSError) {
- let alertController = UIAlertController(title: nil,
- message: error.localizedDescription,
- preferredStyle: .Alert)
- alertController.addAction(UIAlertAction(title: "Dismiss",
- style: .Default,
- handler: nil))
- presentViewController(alertController, animated: true, completion: nil)
- }
當(dāng)查詢產(chǎn)生錯誤時調(diào)用此方法??赡苡捎诰W(wǎng)絡(luò)條件較差或特定CloudKit問題(如丟失或不正確的用戶憑據(jù)或沒有記錄從查詢返回等)發(fā)生錯誤。
當(dāng)處理任何一種遠(yuǎn)程服務(wù)器連接時,良好的錯誤處理是必不可少的。現(xiàn)在,這段代碼只顯示給用戶返回的錯誤信息。
但是,目前程序中存在的非常普遍的問題是:一個是用戶不能登錄到iCloud;另一個是程序還不具有支持用戶自動登錄icloud的功能。建議您自己修改一下errorUpdating(_:)方法使之至少能夠處理這些情況。提示:目前這兩類錯誤都返回1(CKErrorCode)。
現(xiàn)在,請構(gòu)建和運行示例項目。目前,你應(yīng)該看到一個幾近完整的餐館單位名單列表了。
查詢排錯
如果你正在使用iOS模擬器但卻發(fā)現(xiàn)列表控件中沒有填充任何內(nèi)容,那么,你務(wù)必確保從Xcode的菜單項【Debug\Simulate Location\San Francisco, CA, USA】下設(shè)置了正確的位置。如果您需要在Xcode中改變這一位置,那么你可以從應(yīng)用程序的下拉列表中選擇其他位置,從而實現(xiàn)強(qiáng)制刷新而不是被動地等待位置觸發(fā)。
如果您使用的是iPhone或iPad且啟用了定位服務(wù)而列表仍未填充,那么說明餐館沒有足夠接近你當(dāng)前的位置。此時,你有兩個選擇:改變樣本數(shù)據(jù)的坐標(biāo)以便更接近您的當(dāng)前位置;或者使用模擬器來運行應(yīng)用程序。還有第三個選擇,但不是非常實用,即你不得不前往庫比提諾(Cupertino)并進(jìn)入蘋果公司地區(qū)進(jìn)行試驗。
如果數(shù)據(jù)未顯示正確——或者根本不顯示,那么,請使用CloudKit控制面板檢查樣本數(shù)據(jù)。確保所有的記錄都存在,而且你已經(jīng)將它們添加到默認(rèn)區(qū)域,而且它們的值都是正確的。如果您需要重新輸入數(shù)據(jù),那么你可以通過單擊回收站圖標(biāo)刪除記錄(參考下圖)。
調(diào)試CloudKit錯誤有時可能非常棘手。在撰寫本文時,CloudKit錯誤消息中并不包含大量信息。要確定錯誤的原因,您需要查看與你的特定數(shù)據(jù)庫操作相關(guān)連的錯誤代碼。使用數(shù)字錯誤代碼,查找相匹配的CKErrorCode枚舉值進(jìn)行分析。在文檔中的名稱和說明將幫助你縮小問題原因的分析范圍。
【注意】對于可通過CloudKit返回的錯誤代碼列表,請參閱CloudKit框架常量參考(https://developer.apple.com/library/ios/documentation/CloudKit/Reference/CloudKit_constants/#//apple_ref/c/tdef/CKErrorCode)。
下面是一些常見的錯誤枚舉和相關(guān)說明:
- BadContainer——指定的容器是未知的或未經(jīng)授權(quán)的。
- NotAuthenticated——當(dāng)前用戶沒有通過驗證,也沒有用戶記錄可用。如果用戶未登錄到iCloud時可能出現(xiàn)這種情況。
- UnknownItem——指定的記錄不存在。
當(dāng)你得到餐館的名單列表時,你可能已經(jīng)注意到了,你可以看到服務(wù)餐館名稱及其提供的服務(wù)。但沒有顯示圖像!是云端那邊出問題了嗎?
當(dāng)您檢索服務(wù)餐館記錄時,將自動檢索對應(yīng)的圖像。但是,您仍然需要執(zhí)行必要的步驟來將圖像加載到你的應(yīng)用程序中。這需要借助于云端方法了!
使用二進(jìn)制資源
對于二進(jìn)制形式的資源數(shù)據(jù),如圖像,都有相關(guān)聯(lián)的記錄。在本文實例中,你的應(yīng)用程序的資源數(shù)據(jù)都會顯示于MasterViewController表視圖的餐館照片中。
在本節(jié)中,您需要添加邏輯來加載當(dāng)檢索餐館記錄時已下載的資源。
為此,打開文件Model/Establishment.swift,并用下面的代碼更換loadCoverPhoto(_ :)方法:
- func loadCoverPhoto(completion:(photo: UIImage!) -> ()) {
- // 1
- dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
- var image: UIImage!
- // 4
- defer {
- completion(photo: image)
- }
- // 2
- guard let asset = self.record["CoverPhoto"] as? CKAsset,
- path = asset.fileURL.path,
- imageData = NSData(contentsOfFile: path) else {
- return
- }
- // 3
- image = UIImage(data: imageData)
- }
- }
此方法從asset有關(guān)屬性中加載相關(guān)圖片:
1. 雖然你下載了資源,但同時您還檢索了記錄的其余部分?jǐn)?shù)據(jù),因此,你需要使用異步方式加載圖像。如你所見,我們把有關(guān)代碼全部封裝在dispatch_async代碼塊內(nèi)。
2. 資源存儲在CKRecord中,作為CKAsset的實例,所以需要相應(yīng)地轉(zhuǎn)換一下。接下來,從資源提供的本地文件URL中加載圖像數(shù)據(jù)。
3. 使用圖像數(shù)據(jù)來創(chuàng)建UIImage的一個實例。
4. 執(zhí)行與檢索的圖像相關(guān)的completion回調(diào)函數(shù)。請注意,不管執(zhí)行哪一個return語句,延遲(defer)塊都被執(zhí)行。例如,如果沒有圖像資源,那么,在返回時永遠(yuǎn)不會設(shè)置image變量的值,當(dāng)然也就不顯示餐廳對應(yīng)的圖像。
現(xiàn)在,請構(gòu)建和運行示例項目。你會注意到,由于上面的云端操作,現(xiàn)在餐館的圖像顯示出來了!
目前,在CloudKit資源中還存在兩個不足:
- 資源只能在CloudKit中作為記錄屬性存在,你不能把它們單獨存儲。刪除記錄也會刪除所有相關(guān)資源。
- 因為資源與記錄數(shù)據(jù)的其余部分在同一時間下載,所以,獲取資源會產(chǎn)生一定的負(fù)面性能影響。如果您的應(yīng)用程序使用了大量的資源,那么,你應(yīng)該專門存儲一下?lián)碛匈Y源的不同類型記錄的引用。
總結(jié)
到現(xiàn)在為止,你應(yīng)該已經(jīng)看到了我們的最終項目中所提供的功能。目前,該應(yīng)用程序已經(jīng)可以下載餐館記錄,并把它們的詳細(xì)資料和照片加載到程序的表視圖中。
實際上,您還可以從以下幾個方面進(jìn)一步增強(qiáng)本文中的示例應(yīng)用:
允許用戶添加自己的照片、筆記、評論和投訴。這將有助于他們避免再次遭遇不愉快的經(jīng)歷。
允許用戶使用地圖創(chuàng)建一個新的餐館記錄。你可以把這樣的功能添加到Model類中,用于把相應(yīng)記錄保存到公共或私有數(shù)據(jù)庫中。
添加過濾和搜索支持。工程提供的Model類中已經(jīng)構(gòu)建了一個帶有一個距離謂詞的CKQuery,可以把它修改為一個更復(fù)雜的謂詞。當(dāng)然,CloudKit也是支持基于字符串字段的文本搜索的。
提高應(yīng)用程序的性能和數(shù)據(jù)加載體驗。你會注意到,本教程中在一切準(zhǔn)備就緒時使用了一些工具方法來調(diào)用所需的完成處理器函數(shù)。另外,CKDatabase的實例也提供了基于NSOperation的方法來更好地控制API執(zhí)行方式。
為程序提供緩存和同步支持;這樣當(dāng)應(yīng)用程序連接到網(wǎng)絡(luò)時,它能夠保持線下響應(yīng)并保持內(nèi)容***。
使用蘋果公司推出的有著強(qiáng)大后端API支持的CloudKit,相信你能夠把你的應(yīng)用程序提升到一個更高的水平!