SwiftUI 2.0 CoreData 更新的新功能(WWDC20 講稿)

開展白

您好,歡迎來到WWDC。大家好。我是CoreData小組的Rishi Verma。在本次會議中,我們將向您展示如何利用CoreData最適合應用程序的需求。首先,我們將研究如何通過批處理操作快速有效地填充和維護持久性存儲。然後,我們將討論如何定製提取任務以匹配應用程序的需求。最後是一些提示和技巧。應用程序如何對持久性存儲中的更改做出反應。

快速有效地填充和維護持久性存儲。

讓我們先看一下樣本:地震。它是一個Swift應用程序,具有用於驅動UI的視圖上下文和用於提取美國地質調查局提供的數據的背景上下文。我們的示例具有一個本地應用容器,並從USGS收集地震數據作爲JSON提要。

在這裏,我們將JSON feed發送到我們的JSON解析器。依次將數據發送到我們的後臺上下文,以將其轉換爲地震管理的對象,並對我們的本地存儲安全。然後,我們的視圖上下文合併更改以神奇地更新我們的UI。現在,我們的背景上下文可以處理大量創建或獲取的託管對象,這些託管對象僅在保存後不久就被丟棄。但這就是批處理操作的亮點。批處理操作使開發人員可以輕鬆地進行插入,更新和刪除,同時儘可能地少。
由於這些操作的極簡主義性質,因此請注意以下幾點。 沒有發佈保存通知,因爲很顯然我們不在這裏進行保存。由於我們沒有顯露託管對象,所以我們沒有獲得任何回調或訪問器邏輯來進行更改。但是,請耐心等待,您可以持久地解決這兩個警告。啓用持久性歷史記錄並捕獲您的批處理操作,以便可以輕鬆獲取通知,現在我們已經解決了批處理操作的第一個警告。至於回調和訪問器邏輯,我們可以通過分析持久性歷史記錄來適應應用程序當前視圖的相關更改,以適應這種情況。我們如何更深入地進行批處理操作呢?我們的應用程序通常要做的第一件事是將數據加載到持久性存儲中,從而驅動我們的UI。

當我們介紹NSBatchInsertRequest時,它爲開發人員提供了批處理操作以處理數據的能力。它簡化了提取大量數據的能力。現在,我們擴展了NSBatchInsertRequest的功能。最初,我們使開發人員能夠爲批量插入傳遞一系列字典。詞典數組表示要創建的對象,鍵爲屬性名稱及其分配的值。我們還有一個新功能,一個初始化程序,允許開發人員給出一個塊來填寫給定的字典或託管對象。這極大地減少了攝取的峯值內存,同時還進一步減少了對象分配的數量。我們如何看一個例子呢?在這段代碼中,我們正在爲地震創建託管對象。並使用USGS提供的地震數據值填充它們。然後我們保存。讓我們看看如果採用NSBatchInsertRequest的話該代碼的外觀。首先,我們收集所有地震數據的字典並將其添加到數組中。我們創建一個批處理插入請求並執行,很簡單。

現在,讓我們看一下批量插入請求的這種塊變體。我們使用一個塊創建批處理插入請求,該塊將爲給定字典分配值。

然後,我們執行請求,並調用該塊,直到它返回“ true”作爲停止和保存的指示符。但是這三種不同的方式表現如何?讓我們看一下在攝取大量地震時應用程序的性能。當我們使用託管對象保存上下文時,我們看到它花費了超過一分鐘的時間,並且閒置了大約30兆的內存。最初的高峯是JSON數據,而第一分鐘的大部分時間實際上不是攝取,而是變更通知的合併。由於我們進行了大量交易。但是批量插入沒有問題。

當我們使用帶有字典數組的NSBatchInsert時,我們用25兆的空閒內存完成了相同的操作,並且能夠在13秒鐘內保存相同數量的對象,這是傳統保存所需時間的一小部分。但是我們可以做得更好。讓我們使用新的塊攝取,我們能夠在11秒內攝取所有對象。

批處理插入的巧妙技巧

現在,我們已經優化了數據填充,讓我們學習有關批處理插入的巧妙技巧。在這裏,我們從地震樣本中獲得了管理對象模型,並選擇了地震實體。右側是地震實體的數據模型檢查器。讓我們仔細看看。我們可以看到屬性代​​碼是唯一的約束。這意味着持久存儲中只有一個對象可以具有特定的代碼值。沒有其他地震具有相同的代碼值。這對我們的地震樣本有何影響?好了,我們的JSON feed提供了過去30天的所有地震。並且,每當用戶單擊重新加載按鈕時,我們都會從JSON feed中獲取所有數據,這些數據幾乎是相同的,除了最近發生的幾次地震和過去地震的更新數據。

在這裏,我們發生了地震,代碼42來自我們的JSON提要進入解析器。然後將其傳遞到我們的背景環境中,從而將地震42保存到商店中。第一次提取它時,我們在商店中創建了一個新行。但是,在隨後嘗試插入同一地震的過程中,我們不想刪除舊地震並插入新地震。我們真的很想更新任何已更改的數據,在SQL中,這稱爲Upsert。 Upsert是一個SQL術語,如果您同時看到SQL,則更容易理解。因此,這裏我們插入了地震對象,如果在代碼上有衝突,則在插入時,請更新這些屬性,而不要插入。您如何獲得這種行爲?只需在執行對NSMergeByPropertyObjectTrumpMergePolicy的批處理插入請求的上下文中設置合併策略。但是有一種更簡單的更新方法,而批量更新再簡單不過了。使用NSBatchUpdateRequest,無需執行獲取任務即可僅更新託管對象並保存。 NSBatchUpdateRequest可以快速有效地更新滿足Fetch請求中定義的搜索條件的對象中的屬性。讓我們來看一個簡單的例子。使用我們的地震樣本應用程序。如果我們能夠通過其他來源進行確認,我們可以將所有地震標記爲已驗證。但是,讓我們想象一下,如果震級大於2.5,我們的來源只會驗證地震。好吧,我們可以爲此進行批量更新。這段代碼爲地震創建了一個批處理更新請求,然後將屬性設置爲“ updated”(等於)“ true”,並設置謂詞(大於2.5)。然後我們執行批處理更新,我們都完成了。就這麼簡單。因此,我們已經介紹了插入和更新。讓我們進行批量刪除。

批量刪除功能非常強大,可用於輕鬆刪除對象圖的大部分。遵守關係規則。因此刪除將級聯,並且關係將被取消。我們看到的一般用例來自到期代碼,該代碼確定對象的生存時間並清除已到期的對象。這是此API的絕佳用法。但是,看似簡單的操作可能會產生複雜的後果。一個例子呢?這裏有一個例子,地震數據在30天后過期。由於這是一個清理任務,因此我們以後臺優先級異步調度它。我們的塊從託管對象上下文開始,並確定到期日期。

然後,我們構建獲取請求並設置到期謂詞。

使用我們的新提取請求創建批處理刪除請求並執行。嗯但是,如果我們有大量符合批量刪除搜索條件的對象怎麼辦?該請求將對我們的商店進行正確鎖定,時間可能是無限制的。但是,等等,我們可以解決此問題。讓我們設置提取限制。這樣,我們的任務就不會無止境。而且,我們已經使我們的用戶擺脫了很多挫敗感。現在我們已經避免了這種陷阱,讓我們看看如何改善獲取數據的方式。現在我們有了這個豐富的對象圖,我們需要調查並顯示商店中的商品。在獲取數據時,我們返回的數據可以驅動許多視圖和計算。但是我們是否總是需要那麼多數據。又如何在沒有整個對象圖的情況下進行這些複雜的計算呢?首先,managedObjectResultType提供了最輕鬆地遍歷對象圖的最簡單方法。當我們使用結果對批處理結果控制器進行批處理時,這非常好,因爲我們的託管對象已更新,我們的提取結果控制器神奇地響應並應用了差異。讓我們看看實際情況。這是我們的地震樣本,沒有任何數據。然後我們獲取。提取對象時,提取結果控制器將添加行。當我們更新這些對象時,我們的視圖也會更新。但是,如果您在這裏注意到,我們的視圖僅顯示大約15次地震。我們獲得的不只是這些。我們在這裏還有一些改進的空間。在我們的提取任務中說出批量大小。結果僅具有給定數目的對象的第一批完全hyd

如果我們知道結果,我們將需要某些屬性或關係,則可以針對這些要求定製獲取。對於將要訪問的已知屬性,我們可以將屬性設置爲fetch。當我們使用託管對象時,默認行爲是將關係設置爲false,並且關係的第一次遍歷將觸發對相關對象的獲取。

如果遍歷很少的關係或根本沒有關係,那就太好了。但是,如果已知關係很可能會被遍歷,我們建議將鍵路徑設置爲預取,這樣就避免了在以後的時間取回數據,並且由於每次遍歷都加載了錯誤而效率低下。

這是我們的基線提取,空閒時爲17.6 MB。

但是,如果您將屬性設置爲僅提取用戶界面中可見的那些屬性,則可以將空閒內存減少到16.4 MB。現在讓我們談談對象ID。受管對象很大且數據豐富,但是它們並不是在線程之間傳遞的理想選擇,因此當我們要進行工作並確定滿足特定條件的對象時,objectIDResultType會派上用場。這些簡單的標識符可以傳遞給其他線程以進行進一步處理。避免了處理線程上的查找成本。

但是,如果我們需要在完整的受管對象和對象ID之間進行操作,該怎麼辦?像,字典結果。它們非常方便,因爲它們提供了可以傳遞給其他線程的輕量級只讀數據集。字典結果也可以進行定製以進行復雜的數據聚合,從而有助於減少通常需要拉入相關對象圖的大型計算。例如groupBy在實體及其屬性上具有聚合函數。讓我們來看一個例子。平均幅度組按位置。首先,我們確定幅度的關鍵路徑表達式,然後確定函數表達式的平均值。然後,我們對平均幅度進行表達式描述。最後,我們使用屬性設置對地震的獲取任務,以按地點獲取表達式描述和地點組,並將結果設置爲字典。這導致這些結果向我們顯示了地震和指定地點的平均震級。我們要覆蓋的最後一個結果類型是countResultType。

簡單優雅且經過優化。需要我多說?我們已經優化了提取和提取。現在,讓我們看一下如何改善應用程序對持久性存儲中的更改的反應。 CoreData帶有豐富的通知,可讓您知道何時添加或刪除存儲或對象已保存或更改。但是我們要特別關注兩個真正有用的東西。今年,我們引入了對象ID通知,除了傳統的保存通知外,這些通知也可用。對象ID通知與您已經熟悉的託管對象保存通知是輕量級的對等物,該方便的通知是從持久性歷史事務中出售的。讓我們看看Swift中的這些新增功能。現在,受管對象上下文具有針對Swift的現代化通知。我們更新了一些舊有的東西,使它們在Swift中變得更友好,並添加了這兩個新的通知,這些通知使您可以使用對象ID而不是託管對象來驅動應用程序。但這還不是我們現代化的全部。

添加了通知鍵

作爲我們現代化工作的一部分,我們還添加了通知鍵,這些通知鍵使Swift中的通知處理變得更加容易。我們還添加了一些新鍵,以與您的對象ID通知一起使用。我們要討論的另一個通知是遠程更改通知。遠程更改的通知非常有用,因爲任何CoreData客戶端都會將它們發佈給您在過程中和過程外完成的所有操作。

這使您的應用程序避免輪詢更改,並能夠通過通知驅動相同的邏輯。並且,當啓用了持久歷史記錄後,遠程更改通知的用戶信息將包含一個持久歷史記錄令牌,該令牌可用於獲取對象ID通知。

讓我們在作品中看到這一點。在這裏,我們有我們的容器和應用程序,還有一個表,顯示了到目前爲止已捕獲的持久性歷史記錄。

來自USGS的JSON提要上線,並且後臺上下文將JSON數據提取到持久性存儲中。持久的歷史記錄非常詳細地捕獲了操作。遠遠超出我們在這裏可以看到的範圍。

以前,雖然我們的應用程序需要輪詢商店以查找新更改,但不需要使用遠程更改通知。而是被通知已進行了更改,並且遠程更改通知的用戶信息有效負載具有歷史記錄令牌。這樣我可以看到確切的操作和持久的歷史記錄。讓我們看看隨着應用程序的發展,這是如何工作的。

我們的應用程序有一些新的補充。共享擴展名。第二個應用程序利用相同的數據和方便的照片擴展名。當這些新添加的內容之一對持久性存儲進行更改時,將記錄該操作並將其保留在歷史記錄中。但是,當我們的應用程序出現在前臺時,它需要輪詢歷史記錄,這確實非常昂貴。

但是,如果啓用了遠程更改通知,則當我們的應用程序進入前臺時,我們會收到通知。並根據我們的照片擴展名進行後續更改。還有我們的第二個應用程序。還有我們的股票擴展。當我們的應用重新啓動時,它會收到通知,並可以輕鬆查看由於永久歷史記錄而發生的變化。這兩個功能使您很容易知道誰,什麼,何時,何地以及如何更改持久性故事。最後是關於持久歷史的快速提示。關於持久性歷史記錄的一個相當方便的技巧是我們早些時候告訴您獲取請求的說法-請確保根據您的應用程序的需求量身定製請求。在這裏,我們有一個示例,說明如何調整更改請求,以便我們可以找到給定日期後特定對象ID的所有更改。首先,我們從獲取持久性歷史更改對象的實體描述開始。這樣我們就可以使用它來構建獲取請求並設置實體。然後,我們在此處設置謂詞以查找對特定對象ID的更改。然後,我們創建自己的歷史記錄請求並設置獲取請求。瞧,執行!我們的結果將僅是特定日期之後給定對象ID的那些更改。

這就是本屆會議的全部內容。快速回顧。在可能的情況下進行批處理,將獲取的內容定製爲預期用途,並利用通知的功能和

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