[WWDC20 한글번역] Advances in diffable data sources

Munok Kim
12 min readJul 4, 2020

--

개요

이 비디오에서는 iOS 14 용 Diffable Data Source의 발전에 대해 다루고 있습니다.

샘플코드를 실행하면 첫 번째 섹션에는 가로로 스크롤되는 이모지 그리드가 있습니다. 중간에 있는 섹션은 iOS 14의 새로운 기능인 확장/축소 가능한 outline-style UI입니다. 마지막 섹션에는 UICollectionView의 중간에 UITableView처럼 보이는 디자인이 있습니다. 이것이 Emoji Explore 앱 입니다.

iOS 13에 도입 된 Diffable Data Source는 새로운 snapshot 데이터 유형을 추가하여 UI 상태 관리를 크게 단순화합니다. snapshot은 고유 한 섹션 및 item 식별자를 사용하여 전체 UI 상태를 캡슐화합니다. 따라서 UICollectionView를 업데이트 할 때 먼저 새 snapshot을 생성하고 현재 UI 상태로 채우고 datasource에 적용합니다. Diffable Data Source는 앱 개발자에게 필요한 추가 작업없이 차이점을 계산하고 자동으로 애니메이션합니다.

이 API를 WWDC 2019 비디오 “Advances in UI Data Sources”에서 자세히 다루었으며 자세한 내용을 보려면 해당 비디오를 확인하는 것이 좋습니다.

iOS 14의 경우 Diffable Data Source의 기반에서 두 가지 새로운 기능인 Section snapshot과 일급 Reordering 지원을 구축했습니다.

Section Snapshots

기존에 있던 snapshot 타입과 함께 새로운 section snapshot이 생겼습니다. 이름에서 알 수 있듯이 section snapshot은 UICollectionView의 단일 섹션에 대한 데이터를 캡슐화합니다.

이렇게 개선한 것에는 두 가지 이유가 있습니다.

  1. data source를 섹션크기의 덩어리로 구성 할 수 있게 합니다.
  2. outline-style UI 렌더링(iOS14 전체에서 볼 수 있는 공통적인 시각적인 디자인)을 지원하는 데 필요한 계층적 데이터 모델링을 허용하기 위해서 입니다.

이제 Emoji Explorer로 돌아가서 section snapshot을 사용하여 샘플앱을 만드는 방법을 살펴 보겠습니다. 먼저 가로 스크롤 섹션에서 단일 섹션 snapshot을 사용하여 여기에 있는 컨텐츠를 완전히 모델링합니다. 다음으로, 확장/축소 가능한 outline-style 섹션을 볼 수있는 두 번째 섹션에서 두 번째 section snapshot이 이 계층적 데이터를 모델링하는데 사용됩니다. 마지막 list section에서 이 섹션의 내용을 세 번째 section snapshot으로 모델링합니다. 따라서 Emoji Explorer의 경우 단일 섹션의 내용을 각각 나타내는 3 개의 개별 section snapshot에서 Diffable Data Source를 구성합니다.

API를 살펴 보겠습니다. 여기에 새로운 Section Snapshot API의 스니펫이 있으며 전체 API에 대한 SDK를 확인하십시오.

iOS 13에 도입된 원래의 snapshot 타입 (SectionIdentifierTypeItemIdentifierType 가 포함된)과 달리 새로운 iOS 14의 section snapshot의 유형을 살펴보면 제네릭 Item 타입이라는 것을 알 수 있습니다. SectionIdentifierType이 없습니다. section snapshot은 본질적으로 그들이 나타내는 섹션을 모릅니다.

section snapshot에 콘텐츠를 추가하기 위해 append(_:to) API를 사용합니다. 옵셔널 파라미터 parent 가 제공된 경우 계층 데이터를 모델링하는 데 필요한 section snapshot에서 부모-자식 관계를 작성할 수 있습니다.

새로운 section snapshot 타입의 편의를 위해 UICollectionViewDiffableDataSource에 두 개의 새로운 API를 추가했습니다.

먼저, section snapshot과 섹션 식별자를 파라미터로 갖는 apply(_:to:animatingDifferences:completion) 메소드가 있습니다. 두번째로 특정 섹션의 내용을 나타내는 section snapshot을 검색 할 수 있는 새로운 API도 있습니다.

다음으로, Snapshot과 Section Snapshot을 함께 사용하여 콜렉션 뷰의 컨텐츠를 작성하는 방법을 보여주는 코드 스니펫을 작성해 보겠습니다.

  1. Diffable Data Source에 snapshot을 적용하여 원하는 순서대로 섹션을 추가합니다.
  2. 이제 원하는 섹션 순서를 정한 후 section snapshot을 각 섹션에 직접 적용하여 각 섹션에 대한 Item을 채웁니다.

이 Section Snapshot API를 사용하여 계층적 데이터를 작성하는 방법을 살펴 보겠습니다.

  1. append(_:to:) API를 사용하여 "Smileys", "Nature", "Food" 등을 섹션에 루트 항목으로 추가합니다.
  2. 부모-자식 관계를 구성하기 위해 일부 자식 Item을 부모 Item에 추가합니다. 이 예에서 상위 Item은 "Food"입니다.

Child snapshots

계층적 데이터의 일부에 대해서만 추론하는 것이 매우 편리합니다.

이 코드 스니펫에서는 선택적으로 결과 section snapshot에 부모를 포함하여 특정 부모 Item과 관련된 모든 자식을 가져올 수 있습니다.

Expanding and collapsing items

확장 상태는 section snapshot상태의 일부로 관리됩니다. 표시 할 snapshot을 작성할 때 expand/collapse 메소드를 통해 해당 Item의 부모 확장 상태를 설정하여 자식 컨텐츠가 처음에 표시되는지 여부를 쉽게 결정할 수 있습니다. 특정 Item이 확장 또는 축소되는지 isExpanded(_:)으로 확인 할 수도 있습니다. section snapshot의 확장 상태를 변경하면 Diffable Data Source에 실제로 apply(_:to) 할 때까지 적용되지 않습니다.

Section snapshot handlers

사용자가 새로운 Cell Outline Disclosure Accessory로 구성된 outline-styled UI와 상호 작용할 때 프레임워크는 section snapshot을 새로운 확장 상태로 자동 업데이트하고 해당 section snapshot을 데이터 소스에 적용합니다. 종종 이러한 사용자 상호 작용으로 인한 확장 상태 변경에 대한 알림을 받는 것이 유용합니다.

예를 들어, 특정 부모가 절대로 축소되지 않아야 하는 디자인이 있을 수 있습니다. 이를 지원하기 위해 Diffable Data Source에는 애플리케이션이 사용자 상호 작용으로 인한 확장 상태 변경을 프로그래밍 방식으로 제어 할 수있는 새로운 API가 있습니다.

Diffable Data Source에 sectionSnapshotHandlers라는 새로운 속성이 있습니다. 앞에서 언급한 요구 사항을 처리하기 위해 outline의 축소를 피하려면 특정 부모에 대해 false를 반환하는 shouldCollapseItem 핸들러를 제공 할 수 있습니다.

또한 snapshotForExpandingParent API를 사용하여 무거운 컨텐츠의 지연 로딩을 지원합니다. 이는 무거운 컨텐츠를 확보 할 때 초기 section snapshot에 로드되는 컨텐츠의 양을 최소화하는 데 유용합니다. 현재 자식 snapshot의 상태에 따라 필요에 따라 해당 컨텐츠를 로드 할 수 있습니다.

Reordering Support

Diffable Data Source가 가져다 주는 발전 사항 중 하나는 고유 Item 식별자를 사용하여 콜렉션 뷰의 데이터를 모델링하는 기능입니다. 이러한 고유한 Item 식별자를 사용하면 프레임워크가 사용자 상호 작용을 기반으로 애플리케이션을 대신하여 순서 변경을 자동으로 커밋 할 수 있습니다. 그러나 이것은 충분하지 않습니다. 새로운 시각적 순서를 앱의 백업 저장소나 최종적인 소스(source of truth)에 유지할 수 있도록, 사용자가 시작한 재정렬 상호 작용이 발생했음을 앱에 알려야합니다. 그래서 재정렬을 지원하기 위해 Diffable Data Source에는 이제 reorderingHandlers라는 새로운 속성이 있습니다.

이 새로운 API를 통해 재정렬 기능을 사용하려면 canReorderItemdidReorder 클로저를 모두 제공해야 합니다. 사용자가 재정렬 상호 작용을 시작하려고 할 때 canReorderItem 클로저가 호출됩니다. true를 반환하면 재정렬 상호 작용이 시작될 수 있습니다. 사용자가 재정렬 상호 작용을 완료하면 didReorder 클로저가 호출되어 앱이 앱의 최종적인 소스(source of truth)에 새로운 순서 상태를 커밋 할 수 있습니다. didReorder 클로저는 앱에 새로운 타입인 NSDiffableDataSourceTransaction을 전달합니다.

Reordering transactions

트랜잭션은 Diffable Data Source에 대해 수행되는 업데이트에 대해 추론하는 데 필요한 모든 정보를 제공합니다.

NSDiffableDataSourceTransaction을 확인하십시오. 이 유형은 네 가지 기본 정보를 제공합니다.

  1. initialSnapshot : 업데이트가 적용되기 전에 Diffable Data Source의 상태입니다.
  2. finalSnapshot : 업데이트가 적용된 후 Diffable Data Source의 상태입니다. 이 snapshot에서 이러한 Item 식별자를 직접 사용하여 앱의 최종적인 소스(source of truth)에 커밋해야 하는 새로운 순서를 결정할 수 있습니다.
  3. difference : Swift 표준 라이브러리 CollectionDifference 가 지원됩니다. 앱의 최종적인 소스(source of truth)에 Array와 같은 데이터 타입이 있는 경우, 해당 CollectionDifference를 직접 적용 할 수 있습니다.
  4. sectionTransactions : 이 재정렬 업데이트와 관련된 모든 섹션에 대한 섹션 별 세부 정보를 제공하는 섹션 트랜잭션 목록이 표시됩니다. 섹션 트랜잭션도 구성은 상당히 비슷합니다. 재정렬 업데이트와 관련된 각 섹션에 대해 하나의 섹션 트랜잭션이 제공됩니다. 먼저, 이 sectionTransaction이 적용된 sectionIdentifier를 검사 할 수 있습니다. 그리고, 이 섹션의 업데이트와 관련된 CollectionDifference와 함께 초기 및 최종 section snapshot을 볼 수 있습니다.

예를 들어 봅시다. backingStore는 단일 섹션 Collection View에 대한 최종적인 소스(source of truth)를 제공하는 Item의 배열입니다.

트랜잭션과 함께 제공된 Swift 표준 라이브러리 CollectionDifference를 사용하여 새로운 백업 저장소를 만들고 최종적인 소스(source of truth)를 직접 업데이트합니다.

마치며

WWDC20 세션을 번역하여 정리했습니다. 오역이 있을 수 있습니다.

“source of truth”라는게 이번 세션 뿐만 아니라 다른세션에도 자주 나오던데 이게 확실히 이해를 하지못해서 뭐라고 표현해야 할 지 모르겠네요.

RxDataSource와 비슷한 API가 first-party로 나왔습니다. iOS 13부터 존재 했었는데 저는 이제야 알게 됐어요. 이번 iOS 14부터는 개별 섹션과 Item의 계층 또한 지원한다니 샘플앱을 보고 잘 익혀봐야겠습니다.

--

--

Munok Kim

앱 깎는 장인이 되고 싶은 iOS 개발자입니다