이전에 tableView와 collectionView로 리스트를 만드는 실습을 했다. 그리고 오늘은 Diffable data source로 리스트를 구현하는 방법을 공부할 것이다.
지금 구현하는 작은 단위의 프로젝트에선 딱히 diffable의 강점을 체험할 수 없어보인다. diffable data source는 점점 늘어나는 데이터의 변경 사항 처리의 어려움, 복잡한 코드와 성능 저하, 리스트 레이아웃 변경 시 애니메이션 구현이 까다로움..등 때문에 iOS13부터 소개된 새로운 아키텍처인데 나는 아직 복잡한 레이아웃을 구현할 일이 없으며 대규모 데이터를 처리해야할 일도 없다.
https://swiftsenpai.com/development/cells-reload-improvements-ios-15/
따라서 깊게 공부하지는 않을 것이며 컬렉션뷰로 만들었던 리스트를 디파블로 전환해보는 작업까지만 해볼 것이다.
기존 컬렉션 뷰에서는 delegate, datasource, flowlayout 프로토콜을 이용했었다.
diffable data source로 개선하고자 할 때는 이것들도 변경이 된다.
delegate, datasource -> UICollectionViewDiffableDataSource
layout -> UICollectionViewCompositionalLayout
추가) snapshot
이름이 더 길어지고 띄어쓰기도없고 멀미나게 생겼다.
그러나 컬렉션뷰를 처음 배울 때처럼 뒷 부분만 외우면 된다.
diffable data source, compositional layout, snapshot.
내가 실험해보고 싶은 것은
1. delegate,datasource,flowlayout으로 구현했던 부분을 diffable에 대치시켜보는 것
2. 조건에 따라 리스트가 변할 때 애니메이션이 적용됨을 보고싶다
이것을 실험해보기 위한 가상의 상황을 생각했다.
전국에 안경점들이 있고 안경점이 서울인지 아닌지에 조건에 따라 걸러서 표현하고 싶은 상황이라고 가정하고 데이터목록을 만든다.
import Foundation
struct 안경점목록: Hashable { // ⭐️
let name: String
let value: String
}
extension 안경점목록 {
static let 전국: [안경점목록] = [
안경점목록(name: "서울 abc 안경점", value: "영업중"),
안경점목록(name: "서울 bbc 안경점", value: "영업중"),
안경점목록(name: "서울 cbc 안경점", value: "영업중"),
안경점목록(name: "경기 abc 안경점1", value: "영업중"),
안경점목록(name: "대전 abc 안경점2", value: "영업중"),
안경점목록(name: "부산 abc 안경점3", value: "영업중")
]
static func 서울제외() -> [안경점목록] {
var copy = 전국
copy.removeAll { $0.name.contains("서울") }
return copy
}
}
반드시 구조체가 Hashable 프로토콜을 따르게 해줘야한다.⭐️ 그래서 구조체나 클래스가 해시 함수를 사용있게 하고 세트의 원소로서 사용할 수 있게 하는 것이다. 해시 함수는 무엇이고 해셔블~하다는건 무슨 뜻인지 이해하기 어렵다. 이 부분에 대해서는 일단 넘어가도록 한다.
그리고 원본데이터에서 서울을 뺀 목록이 필요하다. 지금 상황에서 원본데이터 중에 서울이 아닌 것은 3줄밖에 되지 않기 때문에 지방만 들어있는 목록을 작성했어도 되지만 원본 데이터가 훨씬 많다는 가정하에 서울을 제거하는 함수로 작성해준다.
대충 리스트를 그려준다. 필요한 것은 컬렉션뷰와 서울을 제외할 액션을 넣어줄 버튼이다. 색감이 끔찍하지만 구조 이해가 빠르기 위해선 확 튀는 색상들로 정해보는 것이 좋은 것 같다. 일부를 한글로 명명하는 것도 같은 이유다.
필요한 것은 diffable data source, snapshot, compositional Layout이다. datasource를 작성하는 방법은 기존 collectionView를 만들 때와 별다를 것이없지만 layout과 snapshot은 새로 알아야한다.
그리고 이 것들을 extension으로 빼주었다. 왜냐면 버튼 액션에 snapshot부분이 필요하기 때문에 갖다써야하는데 뭉터기로 viewDidLoad안에 있다면 꺼내쓰기 곤란하다. 그리고 좀 더 보기 쉬운 이유도 있다.
주황색이 layout, 보라색이 group, label이 item이다. 이런 간단한 실험 상황에선 section과 group의 부분이 모호하다. 그러나 실제 상황에선 아래와 비슷한 모양이 될 것이다.
func updateBtnTitle() {
let title = 보이기 ? "모두보기" : "서울 제외"
btn.setTitle(title, for: .normal)
btn.layer.cornerRadius = 5
}
@IBAction func pressedBtn(_ sender: Any) {
보이기.toggle()
self.안경점데이터 = 보이기 ? 안경점목록.서울제외() : 안경점목록.전국
applySnapshot()
updateBtnTitle()
}
버튼을 뷰컨트롤러에 iboutlet, ibaction으로 연결해주고 버튼을 눌렀을 때의 조건을 넣어준다.
끔찍한 안경점 리스트가 아주 잘 완성되었다.ㅎㅎㅎ