WWDC 보면서 컬렉션 뷰의 바뀐점 등을 작성해보려고 함니다아
참조
https://developer.apple.com/videos/play/wwdc2020/10045
iOS14에서 추가 되었다. 이름에서 알 수 있듯이 섹션 스냅샷은 UICollectionView의 단일 섹션에 대한 데이터를 캡슐화 합니다. 이것을 추가한 이유로는 두가지가 있습니다.

아웃라인 스타일이란 노션의 토글을 생각하면 될 듯? 셀을 클릭 시 해당 셀 하위의 여러 셀들이 보임, 아래 나오는
확장 상태의 의미도 셀을 클릭해서 하위 셀들이 보이는 상태를 의미함.
struct NSDiffableDataSourceSectionSnapShot<Item: Hashable> {
func append(_ items: [Item], to parent: Item? = nil)
func insert(_ items: [Item], before item: Item)
func insert(_ items: [Item], after item: Item)
func delete(_ items; [Item])
func expand(_ items: [Item])
func collapse(_ items: [Item])
var items: [Items] { get }
var rootItems: [Items] { get }
func level(of item: Item) -> Int
}
다음으로 이 새로운 섹션 스냅샷 유형을 사용하기 위해 UICollectionViewDiffableDataSource에 두가지 새로운 API를 추가 하였습니다.
extension UICollectionViewDiffableDataSource<Item, Section> {
func apply(_ snapshot: NSDiffableDataSourceSectionSnapshot<Item>,
to section: Section,
animatingDifferences: Bool = true,
completion: (()-> void)? = nil)
func snapshot(for section: Section) -> NSDiffableDataSourceSectionSnapshot<Item>
}
이제 스냅샷과 섹션 스냅샷을 함께 사용하는 예시 코드를 보겠습니다.
func update(animated: Bool=true) {
// Add our sections in a specific order
let sections: [Section] = [.recent, .top, .suggested]
var snapshot = NSDiffableDataSourceSnapshot<Section, Item>()
snapshot.appendSections(sections)
dataSource.apply(snapshot, animatingDiffereces: animated)
// 원하는 섹션 순서를 지정한 후 섹션 스냅샷을 각 섹션에 직접 적용합니다.
for section in sections {
let sectionItems = items(for: section)
var sectionSnapshot = NSDiffableDataSourceSectionSnapshot<Item>()
sectionSnapshot.append(sectionItems)
dataSource.apply(sectionSnapshot, to: section, animatingDifferences: animated)
}
}
struct NSDiffableDataSourcSectionSnapshot<Item: Hashable> {
func expand(_ items: [Item])
func collapse(_ items: [Item])
func isExpanded(_ item: Item) -> Bool
}
표시할 스냅샷을 만들 때 해당 항목의 상위 확장상태를 설정 하여 하위 콘텐츠가 처음에 표시 되는지 여부를 쉽게 결정할 수 있습니다.
그리고, 스냅샷을 쿼리하여 항목이 확장이나 축소되었는지도 확인이 가능합니다. 또 확장 상태를 변경하면 apply 할 때 까지 적용되지는 않습니다.
사용자와의 상호작용을 통해서 변경이 된다면 알림을 받는것이 유용할 때가 있습니다. 이를 지원하기 위해 DiffableDataSource에는 새로운 API를 추가했습니다.
extension UICollectionViewDiffableDataSoruce {
struct SectionSnapshotHandlers<Item> {
var shouldExpandItem: ((Item) -> Bool)?
var willExpandItem: ((Item) -> Bool)?
var shouldCollapseItem: ((Item) -> Bool)?
var willCollapseItem: ((Item) -> Bool)?
var snapshotForExpandingParent: ((Item, NSDiffalbeDataSourceSectionSnapshot<Item>)
-> NSDiffalbeDataSourceSectionSnapshot<Item>)?
}
var sectionSnapshotHandlers: SectionSnapshotHandlers<Item>
}
그리고, snapshotForExpandingParent를 통해 비용이 많이드는 컨텐츠의 지연 로드도 지원합니다. 이는, 콘텐츠를 가져오는 비용이 많이 들 때 초기 섹션 스냅샷에 로드되는 콘텐츠의 양을 최소화하는데 유용합니다.
따라서 현재 자식 스냅샷의 상태에 따라 해당 콘텐츠를 로드할 수 있습니다.
Diffable Data Source가 제공하는 발전 중 하나는 컬렉션 뷰의 데이터를 고유한 식별자로 모델링하는 기능입니다. 이 고유한 식별자를 사용한다면, 재정렬 변경사항을 자동으로 커밋할 수 있습니다. 하지만 이것으로 충분하지 않습니다.
사용자가 발생시킨 재정렬 상호작용을 앱에 알려야 합니다. 그렇게 해야 앱의 최종 백업 저장소에 대해 새로운 시각적 순서를 유지할 수 있습니다. 이를 지원하기 위해 새로운 속성이 추가되었습니다.
extension UICollectionViewDiffableDataSource {
struct ReorderingHandlers {
var canReorderItem: ((Item) -> Bool)?
var willReorder: ((NSDiffableDataSourceTransaction<Section, Item>) -> Void)?
var didReorder: ((NSDiffableDataSourceTransaction<Section, Item>) -> Void)?
}
var reorderingHandlers: ReorderingHandlers
}
이 새 API를 통해 재정렬을 활성화하려면, 먼저 canReorderItem을 제공해야 합니다.
재정렬이 끝나면 didReorder 클로저가 호출됩니다. 이는 새로운 유형인 NSDiffableDataSourceTransaction를 반환합니다.
struct NSDiffableDataSourceTransaction<Section, Item> {
var initialSnapshot: NSDiffableDataSourceSnapshot<Section, Item> { get }
var finalSnapshot: NSDiffableDataSourceSnapshot<Section, Item> { get }
var dfifference: CollectionDifference<Item> { get }
var sectionTransactions: [NSDiffableDataSourceSectionTransaction<Section, Item>] { get }
}
struct NSDiffableDataSourceSectionTransaction<Section, Item> {
var sectionIdentifier: Section { get }
var initialSnapshot: NSDiffableDataSourceSectionSnapshot<Section, Item> { get }
var finalSnapshot: NSDiffableDataSourceSectionSnapshot<Section, Item> { get }
var dfifference: CollectionDifference<Item> { get }
}
트랜잭션은 DiffableDataSource에 대해 수행되는 업데이트에 관한 정보를 제공합니다.
initialSnapshot은 업데이트 전의 DiffableDataSource의 상태입니다.finalSnapshot은 업데이트가 적용된 DiffableDataSource의 상태입니다.difference는 앱의 진짜 데이터(source of truth)에 배열 같은 데이터 타입이 있는 경우에 해당 CollectionDifference를 직접 적용이 가능합니다.sectionTransactions은 재정렬 업데이트와 관련된 섹션별 세부 정보를 제공하는 섹션 트랜잭션 목록이 표시됩니다.예시코드
dataSource.reorderingHandlers.didReorder = { [weak self] transaction in
guard let self = self else { return }
if let updatedBackingStore = self.backingStore.applying(transaction.difference) {
self.backingStore = updatedBackingStore
}
}
트랜잭션과 함께 제공된 CollectionDifference를 사용하여 새로운 백업 저장소를 만들고 데이터(source of truth)를 직접 업데이트합니다.
혹시 무테이팅에 대해서도 알려주실 수 있나요?