筆記:Develop in Swift Data Collections_Dynamic Data
Published in
22 min readNov 14, 2023
· 學習目標
· 基礎概念
· 1.Adding a Search Controller
· 2.Handling Data Changes
∘ 2–1.比較performBatchUpdates、Diffable Data Sources
· 3.Diffable Data Sources(可差異化的數據源)
∘ 3–1.使用 UICollectionViewDiffableDataSource
∘ 3–2.實作
∘ GitHub
· Lab - iTunes Search (Part 4)
· 1.Review Provided Refactoring
· 2.Add Diffable Data Source for Table View
∘ 2–1.引入 Diffable Data Source:
∘ 2–2.資料類型設定
∘ 2–3.設定 TableView 的 Data Source
∘ 2–4.設定和初始化資料來源
∘ 2–5.創建和應用SnapShot
∘ 2–6.整合到 App 中
· 3.Implement Collection View
∘ 3–1.設計Cell
∘ 3–2.建立Outlet和Layout設計
∘ 3–3.數據源和更新
∘ 3–4.設置數據源方法
∘ 3–5.程式碼重構
∘ 3–6.更新類別定義
∘ 3–7.測試
∘ GitHub
學習目標
- UICollectionViewDiffableDataSource
使用泛型的API,用於管理 CollectionView (如表格和網格)的數據。
它簡化了數據提供流程,自動加入像是數據變動時的動畫這類功能。
- 實作UISearchController:
目的:為 App 添加數據篩選功能。
應用:讓用戶能夠搜尋特定項目或篩選出特定條件的數據。
- 更新
CollectionView
數據
重點:學會在數據有變動時怎麼更新視圖。
方法:通常要觸發視圖的重新加載或更新。
- 建立與運用可擴展數據源(
Diffable Data Sources
):
建立:設定一種可以處理數據變更(增加、刪除、更新)的新型數據源。
使用:用簡單的API來管理 CollectionView 的數據更新。
- 利用可擴展數據源快照
(snapshot)
更新 CollectionView
快照(snapshot):是描述 CollectionView 目前狀態(所有項目和部分)的一種方式。
更新方法:透過應用「新快照」來反映數據變化,無需手動處理每一個細節。
基礎概念
- Diffable data source
(可差異化的數據源)
這是一種特殊的數據源,用於與表格視圖(TableView)或集合視圖(CollectionView)協同工作,
以簡單有效的方式管理視圖的數據和使用者介面。
1. 簡化資料管理:
- 這種數據源幫忙處理 TableView 或 CollectionView 的資料,更輕鬆地管理。
2. 自動比對差異:
- 隨著資料改變,它會自動找出舊資料和新資料的不同,更新視圖。
3. 保持介面整齊:
- 因為它會自己處理資料的變化,所以表格或集合視圖看起來總是整齊有序。
4. 提升效率:
- 這種方法比手動更新資料和介面更省事,節省了寫很多程式碼的麻煩。
5. 動態變化無壓力:
- 不管是加資料、刪資料,還是換順序,這個數據源都能應付自如,而且變化時還會有動畫效果。
- Search controller
1. 標準搜尋介面:
- Search controller 讓使用者可以方便地輸入他們想找的內容。
2. 互動式搜尋框:
- 當使用者在搜尋框打字時,Search controller 會啟動,開始處理搜尋動作。
3. 呈現搜尋結果:
- Search controller 會和專門顯示「搜尋結果控制器」協同工作,確保搜尋結果能夠清楚地展示給使用者。
4. 開發上的便利:
- 這個控制器的設計讓開發者更容易在他們的 App 中加入搜尋功能,不需要從頭開始設計整個搜尋流程。
- Snapshot
(快照)
Snapshot就是在某一時刻,用來呈現 collection view 或 table view 裡面數據的狀態。
1.包含的數據:
- 快照包含想在視圖中展示的各個部分(sections)和項目(items),
並按照我們希望的順序來排列。
2. 配置顯示內容:
- 可以通過添加、刪除或移動這些部分和項目來設置想展示的內容。
3. 應用於可擴展數據源:
- 當配置好快照後,就會應用它到一個可擴展數據源(diffable data source)。
這個數據源會根據「當前數據狀態」和「新快照」之間的差異來進行更新。
UISearchController
和單獨的SearchBar
在功能和用法上的主要差異
一般來說,如果需要更豐富的搜尋功能並且想要與導航結構緊密整合,則 UISearchController 是較好的選擇。
對於更簡單或特定的應用場景,單獨的 SearchBar 可能會更加方便和適合。
1.Adding a Search Controller
- 利用現有的
Navigation Stacks(導航堆疊)
API,整合Search Controller
。因為ViewController
已經嵌入在一個NavigationController
中,所以可以快速加入「搜尋欄界面
」。
- 建立
Search Controller
使用 UISearchController() 初始化搜尋控制器。
如果搜尋結果要用相同的視圖顯示,就不需設置 searchResultsController。
searchResultsController
。- 設定
Search Controller
Search Controller
- 遵循
UISearchResultsUpdating
協定:
為了處理搜尋結果,需要符合 UISearchResultsUpdating 協定。
- 更新搜尋結果的方法 (
updateSearchResults
):
當我們在搜尋欄打字時,會根據輸入的文字更新顯示的內容。
目前的情況是,即使加了搜尋欄,打字進去也不會改變畫面上的內容。
- 搜尋功能實踐:
1. 複製一份原始資料,用來做為搜尋的結果。
2. 過濾這份複製資料,只留下符合搜尋條件的部分。
3. 更新顯示內容,只展示過濾後的結果。
- 程式碼:
1. 增加一個新的變數 filteredItems,這是 items 的一份複製。
- filteredItems 用來儲存過濾後的結果,也會取代 items 成為集合視圖資料的基礎。
2. 把原本Data Source、Delegate Methods 中 items 的地方都改成顯示 filteredItems。
- 實作
updateSearchResults
1. 檢查搜尋欄有沒有輸入文字,而且這些文字不能是空的。
2. 如果有輸入「搜尋條件」,就用 「filter 方法」來找出符合的資料。
3. 使用 localizedCaseInsensitiveContains 來比對文字,不分大小寫。
4. 如果沒有輸入搜尋條件,filteredItems 就會重設為全部的 items。
EX:
- 搜尋字串 “茶” 將匹配到 “伯爵茶拿鐵”,“蜂蜜柚子茶”等。
- 如果沒有搜尋文字,則將 filteredItems 重設為整個 items,以便顯示所有資料集。
- 測試
2.Handling Data Changes
- 改善使用者體驗:
原來情況:使用者搜尋時,資料會突然變更,顯得不夠平滑。
目標:希望能用流暢的動畫效果更新資料,提升使用者感受。
- 實現平滑動畫:
1. iOS 提供特定 API,讓 collection view 和 table view 在更新資料時可以展現平滑動畫。
2. performBatchUpdates(_:completion:) :
- 這個方法可以透過插入、刪除、重新載入和移動 cells(以 IndexPath 標識)來更新資料。
- 實作挑戰:
儘管 performBatchUpdates 很強大,但要計算出「資料集」之間的差異常常不容易。
EX: 如果資料有被移除、移動或新增,要自己寫出這些變化的程式碼既複雜又容易出錯。
- 更簡便的方法:
為了解決這個問題,iOS 提供了一個更簡單、更少出錯的 API。
這個 API 讓處理複雜的資料更新變得簡單,減少手動計算錯誤的風險。
2–1.比較performBatchUpdates、Diffable Data Sources
EX:
- 對於需要高度定制化動畫或者特定的更新邏輯的應用,使用 performBatchUpdates 可能更合適。
- 而對於數據頻繁更新且結構較為複雜的應用,Diffable Data Sources 可能提供更好的解決方案。
3.Diffable Data Sources(可差異化的數據源)
- 慨念
1. 當在 Collection View 或 Table View 中展示靜態資料時,傳統的DataSource方法已經足夠。
2. 若資料會隨著用戶瀏覽而變動,使用 Diffable Data Sources 會是更好的選擇。
3. 「Diffable」指這種資料來源能夠描述「兩組資料」間的差異並進行複雜操作。
3–1.使用 UICollectionViewDiffableDataSource
1. 這是一個實現 「UICollectionViewDataSource」 的具體類別。
2. 它提供了一個基於閉包的API來作為 CollectionView 的資料來源。
3. 使用時,需將資料封裝在 NSDiffableDataSourceSnapshot實例中,然後提供給
Diffable Data Sources 實例。
## 如果是 UITableView 的話可以使用 UITableViewDiffableDataSource
3–2.實作
- 建立 Section 的 Enum:
1. 在 CollectionViewController 中,首先要定義 CollectionView 中會有哪些不同的Section。
這通常是通過建立一個 Enum 來實現的。
EX:
- 如果 CollectionView 只有一種類型的內容,可能只需要一個名為「main」的Section。
2. Enum 需要符合 Hashable 協議,這樣它就可以被用作識別不同 Section 的唯一標識。
- 添加資料來源
(dataSource)
變數:
1. 在 CollectionViewController 中,宣告一個「資料來源」的變數。
- 這是 UICollectionViewDiffableDataSource 的實例,管理和提供資料給 CollectionView。
2. 這個資料來源需要知道 Secction 和 Item 的類型,使用之前定義的「區段列舉」和
項目類型(如String或自定義類型)來指定它。
- 實作資料來源
(dataSource)
:
1. UICollectionViewDiffableDataSource需要兩個參數類型:
- SectionIdentifierType(區段列舉)和ItemIdentifierType(項目的類型)。
2. 需要實作一個閉包來配置每一個Item的視圖(通常是一個cell)。
- 這個閉包類似於之前在 collectionView(_:cellForItemAt:)中所做的,但它還會
接收一個我們的Item類型的實例。
3. 在 CollectionView 的初始化方法中,或在它載入視圖時,創建
UICollectionViewDiffableDataSource的實例。
- 建立和應用快照
(Snapshot)
:
1. NSDiffableDataSourceSnapshot 是用來捕捉 dataSource 在「某一時刻」的狀態。
- 需要創建一個 Snapshot,並將資料(區段和項目)加入到這個快照中。
2. 建立 Snapshot ,並將其應用到 dataSource 上,以便自動刷新相關集合或表格視圖的內容。
- 應用
「新快照」
以反映資料變更:
1. 每當資料發生變化時(例如,用戶透過搜索更改了顯示的資料),需要創建一個「新的快照」
並應用它來更新集合視圖。
2. 這允許 App 動態地更新介面,並能夠以平滑的動畫來呈現這些變化。
- 測試
Lab — iTunes Search (Part 4)
- 練習在 App 靈活地使用
CollectionView
、SearchController
和Diffable Data Sources
。 - 重構的目的:
使用自定義 ContainerViewController:
這個重構版本使用自定義的ContainerViewController。這種控制器能夠在兩個視圖控制器的視圖之間進行切換。
1.Review Provided Refactoring
- 控制器結構
NavigationController:
- 不再是單一的表格視圖控制器,其「根視圖控制器」透過嵌入連接到「表格視圖」和「集合視圖控制器」。
ContainerViewController:
- 位於中間的是 ContainerViewController ,包含了表格視圖和集合視圖。
- 視圖屬性設定:
Outlet:當執行嵌入Outlet時,ContainerViewController 會設定其他兩個視圖控制器的視圖屬性。
- 切換顯示方式:
底部有一個分段控制,用來切換兩個容器視圖的 isHidden 屬性,以此顯示表格或集合視圖。
- 集中管理數據:
StoreItemContainerViewController
- 負責獲取數據並填充表格和集合視圖的數據源。
- 因為兩種視圖使用相同的數據,所以集中在一個視圖控制器中管理數據是合理的。
SearchController
更新:
UISearchController 替代 UISearchBar:
- 現在使用 UISearchController 來替代原本的搜尋欄,配置為始終可見。
- 改善任務管理:
任務變數保存:
- 用來抓取「搜尋項目」的任務現在被保存在變數中,可以在搜尋條件改變時取消。
- 搜尋結果更新方法:
防止過度請求:
- 為了避免每次鍵盤輸入都發送請求,使用了一種叫做「去抖動」(debounce)的技巧,
在用戶停止輸入一段時間後才發送網路請求。
2.Add Diffable Data Source for Table View
- 在
StoreItemContainerViewController
設置異步任務處理
2–1.引入 Diffable Data Source:
- 目前缺少
表格視圖資料來源
的實作,所以App目前還無法展示特別的功能。 - 將會同時為
TableView
和CollectionView
使用Diffable Data Source
。
2–2.資料類型設定
- StoreItem 的設定:
Diffable Data Source
- 將使用 String 作為 SectionIdentifierType。
- 而 StoreItem 作為 ItemIdentifierType。
- 要使用 StoreItem,首先要讓它遵守 Hashable 協議。
- StoreItem 的變化:
除了加入 Hashable,還增加了 trackId 和 collectionId 兩個屬性,以確保 Hashable
的雜湊函數有獨特值。
2–3.設定 TableView 的 Data Source
在 StoreItemContainerViewController 中,增加新屬性以保存 TableView 的 Diffable Data Source。
2–4.設定和初始化資料來源
- 配置 TableView 的 Data Source
1. 添加方法 configureTableViewDataSource(_ tableView: UITableView) 來創建數據源。
2. 使用 cellProvider 閉包來參照 cell 配置的實現。
- 處理圖片加載
圖片加載的管理:
- 在配置方法中,對於每個 cell 加載圖片時,都會檢查並取消之前的圖片加載任務,
確保只加載最新的圖片。
2–5.創建和應用SnapShot
- 快照的計算屬性:
新增計算屬性 itemsSnapshot
- 用於從 items 陣列創建 NSDiffableDataSourceSnapshot<Section, StoreItem>。
- 應用 SnapShot
- 在「搜索結果」變更時,應用這個快照,以獲得更佳的動畫效果。
- 在搜索條件為空或搜索出錯時,也要應用空快照來正確動畫地移除項目。
## 此外取消所有表格是途中未完成的圖片加載任務 ##
2–6.整合到 App 中
- 呼叫配置方法:
在 prepare(for:sender:) 中,擷取 segue 的目標視圖控制器作為
StoreItemListTableViewController,並呼叫「資料來源」配置方法。
- 測試:
3.Implement Collection View
- 接下來是要處理
CollectionView
的單元格(cell)並使用組合式佈局
來實現特定設計。
3–1.設計Cell
使用Stack View:
- 包括 ImageView 和 Lable。
子類別建立:
- 建立一個 UICollectionViewCell 的子類別, ItemCollectionViewCell。
cell 設置:
- 設定cell id 為 "ItemCollectionViewCell",並把它的類別指定為 ItemCollectionViewCell。
3–2.建立Outlet和Layout設計
ItemCollectionViewCell 設置 Outlet:
- UIImageView、UILabel。
- 設置組合式佈局
(CompositionalLayout)
設計中每行有三個項目,每個項目之間有一點空間。
3–3.數據源和更新
建立 CollectionView的 數據源:
- 像 TableView 所做的那樣,使用 itemsSnapshot 更新數據源。
添加 UICollectionViewDiffableDataSource 變數:
- 在 StoreItemContainerViewController 中設置,名稱為 collectionViewDataSource。
3–4.設置數據源方法
- 新方法建立:名為
configureCollectionViewDataSource(_:)
。 - 方法內容:從集合視圖而非表格視圖取得單元格。
創建 configureCollectionViewDataSource 方法:
- 方法內部將從 collectionView 取得cell 。
(與前面製作configureTableViewDataSource的方式一樣)
此外這邊做完,再設置 collectionViewDataSource動畫效果基本上就可以運行了。
3–5.程式碼重構
重構程式碼整理:
- 將 cell 配置程式碼整理成一個方法,讓兩種「數據源」都能調用。
使用協議:
- 建立一個 ItemDisplaying 協議,定義 ItemTableViewCell 和 ItemCollectionViewCell 共有的特性。
協議擴展:
- 在 ItemDisplaying 下加入擴展,讓所有實作此協議的類別都能使用。
3–6.更新類別定義
1. 更新 ItemTableViewCell 和 ItemCollectionViewCell:
- 使它們遵循 ItemDisplaying 協議。
2. 刪除重複的程式碼:
- 在配置數據源的方法中調用新的 configure(for:storeItemController) 方法。
3. 更新 fetchMatchingItems() 方法:
- 同時調用 collectionViewDataSource.apply(_:animatingDifferences:completion:)
和原有的 tableViewDataSource。
3–7.測試
- 確保CollectionView可以正確展示項目,並與TableView的設計效果一致。