DiffableDatasource

나오게 된 이유

앱이 복잡해짐에 따라 controller는 많은 일을 하게 되는데, controller가 복잡해짐에 따라, indexPath로 셀에 넣을 데이터를 지정하는 방식은 오류를 불러일으킬 가능성이 높음. 데이터는 시간에 따라 변하고, UI는 이런 데이터가 변하는 것을 동기화해야 하는데, 이는 오류가 발생하기 쉬운 접근 방식이므로, 이를 해결하기 위해 도입되었다.

Snapshot

UI의 상태이며, DiffableDatasource는 이 snapshot을 이용하여 UI를 업데이트 한다. apply의 인자값으로 전달 collectionView/tableView를 업데이트한다. 각 섹션이나 데이터는 서로를 구분할 수 있는 고유한 식별자가 있어야 하는데, 이를 위해 enum을 사용하거나, hashable을 채택하여 동일한 객체임을 이용해서 UI를 업데이트한다.

UICollectionViewDiffableDataSource / UITableViewDiffableDataSource

전달받은 snapshot 내의 데이터를 이용하여 어떤 collectionView의 셀에 어떤 데이터를 넣을지를 클로저를 통해 전달해 주어서 이를 이용해 사용자가 데이터의 indexPath를 직접 지정해서 넣어주지 않게 해서 좀 더 안전하게 CollectionView의 셀에 데이터를 넣게 해 준다.

CellRegistration

클로저를 통해 collectionView의 .dequeueConfiguredReusableCell(using: , for: , item: )가 호출된면 해당 클로저가 호출되 셀 내부에 데이터를 매핑해줄 수 있게 해 준다.

snapshot이 UI를 업데이트하는 방식

기존 데이터가 있고, A, B, C, D는 각 데이터의 식별자이다. SnapShot은 현재 데이터를 기반으로 UI를 구성하고 있다.

 

그 후 어떤 작업을 통해 데이터가 변경되었다고 해보자.

이 데이터를 snapShot에 넣어 새로 생성하거나, 기존 snapshot의 데이터를 변경시킨 후, datasource에 apply를 시킨다.

let data // 기존과 다른 데이터
var snapshot = NSDiffableDataSourceSnapshot<섹션타입, 데이터 타입>()
snapshot.appendSections([.main])
snapshot.appendItems(mountains)
dataSource.apply(snapshot, animatingDifferences: true)

데이터소스가 snapshot을 전달받으면 전달받은 데이터의 수만큼 클로저(cellProvier)를 호출한다. 각 섹션과 데이터는 snapshot에서 지정을 했기에, 인자값으로 컬렉션뷰와 indexPath, 그리고 해당 indexPath에 해당하는 셀에 적용할 데이터가 전달된다.

dataSource = UICollectionViewDiffableDataSource<섹션 타입, 데이터 타입>(collectionView: 업데이트할 콜렉션 뷰) {
            (collectionView: UICollectionView, indexPath: IndexPath, identifier: 데이터 타입) -> UICollectionViewCell? in
            // Return the cell.
            return collectionView.dequeueConfiguredReusableCell(using: cellRegistration, for: indexPath, item: identifier)
        }

DiffableDataSource에서 셀에 데이터를 매핑해도 되지만, dequeueConfiguredReusableCell을 호출하면 CellRegistration의 클로저가 호출되면서 셀에 데이터를 매핑하는 코드를 분리할 수 있다.

이 과정이 완료되면 UICollectionView가 업데이트된다.

전체 과정

전체적인 코드를 보면 사용자가 어떤 섹션에 어떤 데이터를 선택해서 셀에 매핑하는 코드가 없다. snapshot에 section과 데이터를 넣고, diffableDatasource에서 어떤 컬렉션 뷰에서 어떤 데이터와 섹션을 사용할지 정의를 하고, 클로저로 indexPath와 cell, data를 전달받아 셀에 매핑한다. 개발자는 데이터만 전달하면 DiffableDataSource에서 셀의 idnexPath와 해당 indexPath의 데이터를 클로저로 전달해주니, 오류가 발생할 확률이 낮아진다.