iOS13에서 Diffable DataSource와 Compositional Layout 이라는 새로운 컴포넌트가 등장했다.
iOS14부터 새로운 기능을 도입할 수 있는데, 먼저 Diffable DataSource를 살펴보면
게다가 추가 작업 없이 그 차이를 계산하고 애니메니션을 자동으로 생성해주기도 한다고 한다.
Diffable은 무엇을 뜻하는걸까?
뷰의 항목을 업데이트할 때마다 컬렉션뷰가 업데이트된 컬렉션과 이번에 표시된 컬렉션 간의 차이를 자동으로 계산한다는 것을 의미한다.
애니메이션
데이터를 추가, 업데이트, 삭제할 때마다 자동으로 데이터 변경 애니메이션이 적용된다.
자동 데이터 동기화
UI 데이터의 동기화 부분 대신 앱의 동적인 데이터와 내용에 집중할 수 있다.
Centralized Truth를 사용하기 때문에 UI와 데이터소스간의 Truth가 맞지 않아 크래시가 발생하는 일이 없음
코드감소
전반적으로 더 적은 코드를 작성할 수 있다.
Diffable DataSource가 나오기 전에도 테이블뷰를 문제없이 그렸는데, 왜 디퍼블 데이터소스를 사용해야 하는걸까?
아마 iOS앱을 개발한다면 테이블뷰를 그리다 아래와 같은 에러를 만난 경험이 있을것이다. 섹션 수가 잘못되어 앱이 강제종료 되는 경우이다.
어쨌든 해당 에러는 데이터의 변경 사항을 수동으로 관리하고 동기화 할때의 문제점을 나타낸다고 할 수 있는데,
이 문제는 tableView.reloadData()를 이용하여 해결할 수 있다.
그런데도 왜 DiffableDataSource가 필요한걸까?
reloadData()의 경우 모든 셀을 다시 그리면서 테이블뷰를 한번에 업데이트 하므로 UI가 애니메이션 없이 부자연스럽게 변경된다.
→ 사용자 경험 저하로 이어질 수 있음
하지만 Diffable DataSource와 함께하면 아래와같이 빠르고 매끄럽고 자연스럽게 테이블뷰를 그릴 수 있다는 것이다.
compositional layout은 빠르고 유연하고, composable하게 컬렉션뷰를 구현할 수 있는 컬렉션뷰 레이아웃의 한 종류이다.
컴포지셔널 레이아웃은
Compositional Layout 역시 iOS13에서 도입되었고 item, group, section으로 구성되어있다.
하나의 셀을 item, 아이템의 집합을 group, 그룹의 집합을 section이라고 한다.
섹션 스냅샷을 사용하여 뷰를 업데이트 하고 레이아웃을 구성하는 방법까지 공부하고 내 프로젝트에 적용해보았다.
HighwayInfo를 만들때 휴게소 화면을 어떻게 구현했는지 예시와 함께 설명해보면
휴게소 섹션은 한개의 그룹, 한개의 섹션으로 이루어져 있고
그룹의 가로는 화면의 넓이의 절반, 높이의 1/4정도 된다
이 화면을 그리기 위해
// item
let itemSize = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .fractionalHeight(1))
let item = NSCollectionLayoutItem(layoutSize: itemSize)
// group
let groupSize = NSCollectionLayoutSize(widthDimension: widthDimension, heightDimension: heightDimension)
let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item])
// section
let section = NSCollectionLayoutSection(group: group)
section.orthogonalScrollingBehavior = .continuousGroupLeadingBoundary
group의 가로/세로는 각각 0.5, 0.25로 설정하고 horizontal 레이아웃을 적용해주었다.
아이템은 그룹을 꽉 채우도록 fractionalWidth, fractionalHeight를 각각 1.0으로 설정했다.
섹션의 orthogonalScrollingBehavior를 주어 좌우로 스크롤 되는 레이아웃으로 구현해보았다.
헤더뷰도 Compositional Layout으로 구성 가능한데,
아래 뷰를 구성하기 위해
// header
let titleSupplementary = NSCollectionLayoutBoundarySupplementaryItem(
layoutSize: titleSize,
elementKind: "title-element-kind",
alignment: .top)
section.boundarySupplementaryItems = [titleSupplementary]
이렇게 헤더를 만들고 섹션의 boundarySupplementaryItems 에 지정해주면 된다.
위 화면을 그리기 위해 데이터소스를 어떻게 구현했는지 알아보자.
여기에서 어려웠던 점은 내앱의 경우 하나의 컬렉션뷰가 세개의 셀을 나타내야 했기 때문에 food, convenience, brandList 모두 등록해주었는데
저장된 데이터를 꺼내 뷰에 나타낼때 item의 타입을 한개로만 정의할 수 없었다는 점이다.
💡 고민하던 중 FoodMenu, ConvenienceList, Brand 모두 Hashable을 채택했다는 점을 깨닫고 item의 타입을 AnyHashable로 적어주어서 해결했다.
그렇게 해서 완성된 뷰가 휴게소 상세보기 화면 이다
WWDC2020 컬렉션뷰 레퍼런스를 보면서 왜 테이블뷰도 아니고 컬렉션뷰이지? 라는 궁금증이 생겼는데
iOS14의 경우 Composition Layout을 기반으로 Lists라고 하는 새로운 기능이 추가된 것을 보면 알수있다.
실제로 2020 WWDC를 보면 UICollectionLayoutListConfiguration에 대한 이야기가 나오는데, iOS14부터 사용 가능한 ListConfiguration을 소개하는것을 알 수 있다.
UICollectionLayoutListConfiguration을 사용하면
이렇게 간단한 코드로
이런 테이블 뷰 리트스 뷰를 만들 수 있다고 하니
언젠가는 컬렉션뷰가 테이블뷰를 대체하고, UITableView관련 API들이 deprecated 될 수도 있겠다는 생각이 들었다.
ListConfiguration은 Compositional Layout 위에서 작동하며 UICollectionViewListCell, header, footer, sidebar를 모두 제공한다고 하는데 테이블뷰가 남아있을 이유가 있을까
Diffable DataSource와 Compositional Layout을 처음 사용해보았는데, 너무 만족스럽다.
새롭게 접하는 개념들이라 낯설고 적용하기 어려울것같다는 우려와는 다르게 사용법도 생각보다 쉬웠다.
제일 좋은점은 기존에 extension으로 컬렉션뷰 UICollectionViewDelegate를 채택하고, 관련 데이터소스와 델리게이트 매서드를 정의해준 부분이 없어졌다는 것이다. 코드가 길고 복잡해서 한눈에 알아보기 어려웠는데 DiffableDataSource는 컬렉션뷰 관련 코드를 한곳에서 관리할 수 있어서 가독성이 높아진거같다.
또 달라지는 데이터만 알아서 다시 그려주니 간편하고 UI업데이트가 자연스러운 점도 장점이다.
참고