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)를 직접 업데이트합니다.
혹시 무테이팅에 대해서도 알려주실 수 있나요?