SwiftUI 2.0 CoreData通過CloudKit同步公開數據庫(WWDC20 講稿)

CoreData通過CloudKit同步公開數據庫

CoreData通過CloudKit同步公開數據庫

您好,歡迎來到WWDC。

嗨,我叫尼克·吉列(Nick Gillett)。我是蘋果公司核心數據團隊的一名工程師,今天我們將討論使用NSPersistentCloudKitContainer構建應用程序(將核心數據存儲與公共CloudKit數據庫同步)的感覺。爲此,我們將引入一些新的API,並且會討論很多有關爲公共數據庫構建應用程序時需要考慮的事項。最後,我們將詳細研究如何使用公共數據庫中的NSPersistentCloudKitContainer進行導入。

現在,在我們開始之前,我想快速回顧一下到目前爲止。在2019年的“使用CloudKit使用核心數據”會話中,我們引入了NSPersistentCloudKitContainer,以輕鬆地將您的核心數據存儲與私有CloudKit數據庫同步。同樣,我們引入了一個新的示例應用程序來演示其工作方式,並且編寫了大量有關NSPersistentCloudKitContainer如何工作以及如何將其與應用程序集成的文檔。因此,如果在本屆會議期間的任何時候覺得您缺乏上下文或我們正在討論的某些概念感到陌生,我強烈建議您閱讀我們的文檔和上一屆會議。我也想複習一些條款。您會看到,Core Data和CloudKit是非常相似的框架,它們通過相似的想法和API來表達自己。我們從對象,模型和存儲方面考慮每個框架。在Core Data中,我們將它們稱爲NSManagedObject的實例,並且它們是您直接在應用程序中使用的對象。同樣在CloudKit中,我們將它們稱爲CKRecord。

我們爲這些對象建模或使用NSManagedObjectModel的實例描述它們,在CloudKit中,這稱爲架構。最後,在NSPersistentStore實例中或在CloudKit中,作爲CKRecord數據庫一部分的CKRecordZone,對象是持久性的(使用本地數據)。現在我們已經解決了這個問題,我想向您展示實際構建應用程序的感覺,或者在這種情況下,定製與公共CloudKit數據庫一起使用的應用程序。爲此,我將打開示例應用程序,並在尋找一個名爲Core Data Stack的特定文件。您會看到Core Data堆棧是該應用程序保留設置其NSPersistentCloudKitContainer實例所需的所有代碼的地方。您可以在頂部看到它已經在使用NSPersistentCloudKitContainer,這意味着它已經準備好與私有數據庫同步。現在,要使其與公共數據庫一起使用,我們只想添加一行新代碼。我只是要更改現有商店描述以設置其cloudKitContainerOptions,並使用新的databaseScope屬性將其設置爲public。

您可以看到我剛剛粘貼了很多代碼,因此讓我們詳細瞭解一下這裏實際發生的情況。在這段代碼中,我們創建了一個新的NSPersistentStoreDescription實例,並使用常規的cloudKitContainerOptions對其進行了自定義-歷史跟蹤和遠程更改通知之類的東西。

然後,我們創建一個新的NSPersistentCloudKitContainerOptions實例。

這就是告訴NSPersistentCloudkitContainer我們要將此存儲描述與CloudKit一起使用的原因。我們將其databaseScope屬性設置爲public,這表明它要與公共數據庫一起使用。

接下來,我們將cloudKitContainerOptions分配給商店描述,並將商店描述附加到我們希望NSPersistentCloudKitContainer加載的商店數組中。最後,我們像平時一樣加載商店。現在,我想說的就是所有要做的,但是我們必須配置CloudKit容器以使其與NSPersistentCloudKitContainer一起正常工作。您會看到它在公共數據庫中獲取數據的方式有所不同。因此,我現在想使用CloudKit儀表板來更改架構的配置。爲此,我要打開Safari,您會看到我已經有需要在Safari中打開的頁面。因此,讓我們將自己定位在當前位置。在頂部,您可以看到我已經爲示例應用程序選擇了iCloud容器,並且我們處於開發環境中,專門研究架構。我們正在查看模式的索引部分,因爲我們需要向您在屏幕左側列出的所有五種記錄類型中添加一些索引。我們需要爲每個記錄類型添加兩個新索引,然後,我將在此處使用此“添加索引”按鈕。我將單擊一次,爲recordName添加一個,然後爲ModifyAt日期添加另一個,最後我將保存更改。這些是NSPersistentCloudKitContainer對公共數據庫運行其查詢以獲取此類型的記錄所需的索引。當然,現在對於您的應用程序,您將必須對所有記錄類型重複這些步驟,因此我們將對示例應用程序再做四遍。這就是我們構建與公共CloudKit數據庫一起使用的應用程序所需要做的全部工作。

我們只需採用NSPersistentCloudKitContainerOptions的新databaseScope屬性,併爲所有記錄類型添加幾個索引。現在,如果您沒有在CloudKit儀表板中看到所有索引,則可能需要執行一個稱爲架構初始化的過程。

模式初始化將在我們的文檔以及2019年的會議中詳細介紹。完成此操作後,您將在運行應用程序的設備上擁有CloudKit中所有數據的完整本地鏡像。

現在您可能想知道爲什麼我們要創建一個完整的本地鏡像。原因是-您要求我們這樣做。您會看到,自2019年我們的演講以來,我們收到了許多功能請求以支持公共數據庫,並且它們有一些共同的主題。首先是所有請求都希望創建一個每個人都可以使用的數據集-也就是說,應用程序的所有用戶都可以訪問。現在有時這是您(開發人員)將創建的數據,例如應用程序模板或初始數據集,因此用戶從第一天開始就對您的應用程序具有豐富的經驗。在其他情況下,則是用戶創建的數據。現在,我將在這裏坦率。爲此,我們最常見的要求是在視頻遊戲中獲得高分,這實際上是我們希望NSPersistentCloudKitContainer支持的一個很好的例子。您需要本地所有數據,以便您可以快速獲取,排序,排序數據,而這正是您的用戶想要貢獻的。我們也知道您想根據這些應用程序的需要來混合私有數據庫中的數據。這很有道理。您的用戶可能想要上載他們的高分,但他們可能不想上載他們保存的遊戲狀態或角色配置到公共數據庫。而要同步,您將使用私有數據庫。

這實際上是我們下一節的主要內容,是在構建與公共數據庫一起使用的應用程序時需要考慮的特殊注意事項或事項。爲了深入探討這一點,我們將比較和對比使用私有數據庫和公共數據庫時NSPersistentCloudKitContainer的行爲。

我們要看的第一件事是帳戶和所有權的概念,以及兩者之間的關係。您會看到,在私有數據庫中,必須有帳戶,並且所有數據都由一個用戶擁有,因此行爲相當簡單,但公共數據庫卻無法正常工作。

帳戶是可選的。您可以在沒有iCloud帳戶的情況下從公共數據庫讀取數據,並且該數據可以由您的應用程序的任何用戶擁有。

我們還將討論導入以及公共數據庫和私有數據庫之間的導入方式。您會看到私有數據庫支持推送通知,而公共數據庫則不支持,因此我們必須使用稱爲輪詢的過程來查詢要導入的記錄。現在我想在這裏喊出口,因爲我們不會談論它。在私有數據庫和公共數據庫之間,它的工作方式相同。我們在2019年的會議中詳細討論了此問題。當我們考慮帳戶和所有權時,我們真正要談論的是登錄或註銷iCloud時應用程序可以執行的一組操作帳戶。現在,正如我所說,在私有數據庫中,這非常簡單。如果您已退出,則無法執行任何操作。如果您已登錄,則可以執行所有操作。世界是您的牡蠣,所有數據都是您的工作之本。但是在公共數據庫中,這變得更加複雜。如果您已登出或登錄,則可以讀取數據,但是如果您登錄到iCloud帳戶,則只能創建數據-新記錄。那修改呢?好吧,這很棘手。對於像我們的示例應用程序那樣具有UI的應用程序,這帶來了一個問題。

也許您有一些編輯控件,例如,左上角的“編輯”按鈕或右上角的“ +”按鈕,使我們可以創建新記錄。同樣,我們的示例應用程序具有一個Detail視圖控制器,該控制器允許我們編輯單個對象,並且還具有編輯控件。我們的應用程序可能需要根據該對象的存儲位置或該對象所在的數據庫來知道是否可以使用這些控件中的一個或任何一個。事實證明,可以使用NSPersistentCloudKitContainer的現有API來解決此問題。您只需向CloudKit詢問當前帳戶即可。然後,您要求NSPersistentCloudKitContainer提供支持您正在使用的對象的記錄。而且,如果您比較創建者的UserID,那麼您將知道該對象是否可變。

但是,僅要將這個問號變成是或否,這是荒謬的代碼量,並且對於應用程序中的每個用戶界面元素而言,這都是瘋狂的代碼量。這樣我們可以做得更好。我們有。這是NSPersistentCloudKitContainer的新canUpdateRecord forManagedObjectWithID方法,該方法確切地告訴我們我們需要了解關於該對象相對於設備的當前配置是否可變,該對象所保存的持久存儲以及該存儲是否爲可變對象由CloudKit支持。它甚至可以處理您可能期望的所有極端情況,例如將對象存儲在完全不受CloudKit支持的商店中,或者在您使用應用程序時在設備上更改帳戶。並且我們緩存了此狀態,以使其在用戶界面中足夠有效。現在,如果您有一個更核心的世界屏幕視圖(例如我們的應用程序中的此表視圖),則可以在存儲中使用NSPersistentCloudKitContainer的canModifyObjects來判斷給定持久性存儲中的任何對象是否相對於設備上的配置以及該商店是否受CloudKit支持。現在,我想稍作調整,並詳細討論如何在NSPersistentCloudKitContainer的公共數據庫中進行導入。爲此,我想回顧一下我們在2019年的會議中的一些內容。您可能還記得這張圖,其中我們討論瞭如何從CloudKit收到推送通知時,我們安排了一個導入操作,該操作將所有已更改的記錄彙總到本地商店,並使它們可用於您的應用程序。

即使您有大量的更改記錄集或非常複雜的對象圖,此方法也能很好地工作。無論您使用的是公共數據庫還是私有數據庫,NSPersistentCloudKitContainer都能有效地導入複雜的圖形和較大的更改集。爲了瞭解它們之間的不同,我們想看看雲與本地持久存儲之間到底發生了什麼。當我說我們創建導入操作時,我的真正意思是我們創建了CKFetchRecordsZoneChangesOperation的實例,並且這對CloudKit服務器創建了一個請求,該請求從私有數據庫中刪除了所有已更改的記錄。但是CKFetchRecordsZoneChangesOperation依賴於專用於私有數據庫的某些技術,因此在公共數據庫中,我們必須改用CKQueryOperation。現在,如果您曾經使用過CKQueryOperation,您就會知道查詢會影響特定的記錄類型,這意味着我們必須針對該帖子發出一個請求,針對其標籤發出另一個請求..對於附件發出另一個請求...要求提供圖片...以及另一個要求多對多關係的請求。等等。它一直持續到我們獲取應用程序中的所有記錄類型爲止。

這意味着由公共數據庫支持的存儲的公共數據庫正在做更多的工作。這就是我們將數據導入公共數據庫的方式。

NSPersistentCloudKitContainer必須使用CKQueryOperation而不是CKFetchRecordsZoneChangesOperation,並且我們必須輪詢更改,而不是使用推送通知來確切知道何時發出請求。

現在這意味着我們需要謹慎對待如何加載CloudKit服務器,因爲我們希望您的應用程序隨公共數據庫擴展的方式。

因此,我們僅在應用程序啓動時或大約每30分鐘使用應用程序後輪詢一次更改。這是爲了確保我們將這些請求的負載與您的應用程序的實際使用情況保持一致。

當然,這確實意味着您可以從公共數據庫獲得的新鮮度質量與私有數據庫明顯不同。

即使您有大量的更改記錄集或非常複雜的對象圖,此方法也能很好地工作。無論您使用的是公共數據庫還是私有數據庫,NSPersistentCloudKitContainer都能有效地導入複雜的圖形和較大的更改集。爲了瞭解它們之間的不同,我們想看看雲與本地持久存儲之間到底發生了什麼。當我說我們創建導入操作時,我的真正意思是我們創建了CKFetchRecordsZoneChangesOperation的實例,並且這對CloudKit服務器創建了一個請求,該請求從私有數據庫中刪除了所有已更改的記錄。但是CKFetchRecordsZoneChangesOperation依賴於專用於私有數據庫的某些技術,因此在公共數據庫中,我們必須改用CKQueryOperation。現在,如果您曾經使用過CKQueryOperation,您就會知道查詢會影響特定的記錄類型,這意味着我們必須針對該帖子發出一個請求,針對其標籤發出另一個請求..對於附件發出另一個請求...要求提供圖片...以及另一個要求多對多關係的請求。等等。它一直持續到我們獲取應用程序中的所有記錄類型爲止。

這意味着由公共數據庫支持的存儲的公共數據庫正在做更多的工作。這就是我們將數據導入公共數據庫的方式。

NSPersistentCloudKitContainer必須使用CKQueryOperation而不是CKFetchRecordsZoneChangesOperation,並且我們必須輪詢更改,而不是使用推送通知來確切知道何時發出請求。

現在這意味着我們需要謹慎對待如何加載CloudKit服務器,因爲我們希望您的應用程序隨公共數據庫擴展的方式。

因此,我們僅在應用程序啓動時或大約每30分鐘使用應用程序後輪詢一次更改。這是爲了確保我們將這些請求的負載與您的應用程序的實際使用情況保持一致。

當然,這確實意味着您可以從公共數據庫獲得的新鮮度質量與私有數據庫明顯不同。

現在,我還要提及的是,這意味着更簡單的託管對象模型(即其中包含較少實體的託管對象模型)對公共數據庫的請求將更少。這並不是說您的應用程序中不應包含複雜的對象圖,或者公共數據庫不支持它們。實際上,您絕對應該。您應該構建公共數據庫所需的管理對象模型,但這確實意味着您應該將該模型限制爲僅在公共數據庫中使用的實體,這樣NSPersistentCloudKitContainer不會發出不必要的請求。現在,我們使用管理對象模型中的配置來執行此操作,並在文檔中詳細討論有關如何設置要在NSPersistentCloudKitContainer中使用的管理對象模型的內容。您想將使用公共數據庫的實體限制爲該存儲的特定配置。現在爲什麼有什麼關係呢?好吧,因爲查詢會影響刪除如何在整個公共數據庫中傳播。考慮以下對象集。

如果我們將這些對象導入到兩個設備上,則這兩個設備將像我們期望的那樣對雲中的內容完全相同。對?在私有數據庫中,如果我們從一臺設備上刪除一個對象,然後將該刪除操作導出到雲中,則會留下一個稱爲墓碑的外殼,其中包含記錄類型和已刪除對象的記錄ID。

現在,當我們從私有數據庫中導入更改並在另一臺設備上刪除該記錄時,這使我們能夠通過CKFetchRecordZoneChangesOperation來獲取該邏輯刪除,因此兩臺設備再次呈現出雲中的相同圖片。但是,正如我所說,NSPersistentCloudKitContainer不能將CKFetchRecordsZoneChangesOperation與公共數據庫一起使用。

它必須使用CKQueryOperation。

因此,當我們從一臺設備刪除記錄並將該刪除內容導出到公共數據庫時,該記錄將立即被刪除。通過查詢操作,我們詢問公共數據庫發生了什麼變化。它什麼也沒說。

沒有遺留下來供我們取用。這意味着我們無法將刪除的內容傳播到另一臺設備,它們將對雲中的內容有不同的瞭解。這給應用程序帶來了潛在的問題,尤其是當它們具有這樣的用戶界面時,例如在表視圖中我們可以滑動刪除。滑動刪除該對象時,該刪除不會在公共數據庫中傳播到已下載此對象的所有設備。事實證明,使用CKRecordZone上的API(稱爲功能)可以完全檢測到這種情況的發生。

如果某個區域不支持fetchChanges功能,則無法使用CKFetchRecordsZoneChangesOperation對其中的重要數據進行處理。我們必須改爲使用查詢。但這需要花費大量的代碼才能集成到您的應用程序中,我什至不用費心把它放到幻燈片上。相反,我們可以使用NSPersistentCloudKitContainer的新canDeleteRecord(forManagedObjectWithID)方法在一行代碼中檢測到這一點。如果返回false,則意味着該記錄存儲在公共數據庫中,並且NSPersistentCloudKitContainer無法以與從私有數據庫相同的方式導入刪除。因此,刪除操作不會傳播到已下載此對象的所有設備。現在,這並不意味着刪除根本不起作用。因爲NSPersistentCloudKitContainer必須使用CKQueryOperation來獲取對象,所以您需要確定應用程序是嘗試刪除對象還是要從UI中刪除對象。現在,這並不意味着您無法刪除。實際上,您絕對需要刪除數據,但是爲了從公共數據庫中刪除數據和從應用程序的用戶界面中刪除數據,刪除數據之間存在區別。在這段代碼中,我們使用canDeleteRecord(forManagedObjectWithID)告訴我們是否應該更新一條記錄以將其從用戶界面中刪除,而不是刪除它。爲此,當我們無法從公共數據庫中刪除某些內容時,我們將此標籤上的isTrashed屬性設置爲“ true”,並且在我們的應用程序中,我們使用帶有謂詞的訪存請求,該謂詞過濾掉所有被破壞的記錄以將其從中刪除。用戶界面。這樣,我們使用更新或修改來代替刪除,以在我們的用戶界面中實現所需的效果。現在,我們可以進一步推廣這種範例。舉例來說,將記錄中的所有字段一經刪除就不再需要了。這樣可以保留...從而回收公共數據庫以及用戶設備磁盤上的空間,並且一旦您確信所有下載的這些記錄已經處理了此更新。因此,您在應用程序中真正需要確定的是-是否要從公共數據庫中刪除某些內容,以便沒人再次下載?還是要從UI中提取某些內容?在本課程中,我們學到了很多有關NSPersistentCloudKitContainer的知識,包括其新的databaseScope API,該API允許您配置是將商店用於公共數據庫還是私有數據庫。我們詳細研究了公共數據庫對您的應用程序意味着什麼。最後,我們瞭解了其他一些NSPersistentCloudKitContainer API,以及它們如何幫助您簡化其中的一些注意事項。

這就是關於NSPersistentCloudKitContainer和公共數據庫的全部內容。

推薦文章

CoreData篇

Combine篇

TextField篇

JSON文件篇


一篇文章系列

技術交流

QQ:3365059189
SwiftUI技術交流QQ羣:518696470

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章