→ Shook

[Project-Shook] DiffableDataSource, CollectionView

Swift librarian 2024. 12. 4. 15:16

🔥 문제 상황

썸네일이 바뀌지 않는다!!!

  • 새로고침을 해도 썸네일이 바뀌지 않는 상황이 발생했습니다.

🤔 원인

  • 콜렉션뷰의 DataSource에 전달해주는 값은 urlString으로 일정하기 때문입니다.
  • 라이브 스테이션은 동일한 urlString으로 이미지만 바꿔주는 형식으로 작동하기 때문입니다.

💡 해결 과정

🧑🏻‍💻 모든것을 Fetch 해오자!

  • PR 링크
  • Fetch 할때 이미지를 내려받아 dataSource에 넣어준다면 image자체가 바뀌었기 때문에 dataSource를 업데이트 해줄 수 있었습니다.
채널 정보 및 URL 가져오기 → 가져온 URL로 이미지 로드하기 → apply snapshot

👀 새로 생긴 문제 상황

  • 모든 이미지를 그때그때 받아보다보니 속도 저하 문제가 생겼습니다.

  • Channel 모델에 불필요해보이는 URLString, UIImage 속성이 둘다 포함되는 상황
public struct Channel: Hashable {
    let id: String
    let name: String
    var thumbnailImageURLString: String
    var thumbnailImage: UIImage?
    let owner: String
    let description: String
}

🧑🏻‍💻 URLString만 받아와서 셀 업데이트를 무조건 하게 하자!

  • 데이터를 받아온다면 무조건 reload하는 방식을 채택해보았습니다. Channelimage속성도 지웠습니다.
썸네일 바꾸기 성공!
// 변경 전
dataSource.?.apply(snapshot, animatingDifferences: true)

// 변경 후
dataSource?.applySnapshotUsingReloadData(snapshot)
  • 기존에 Cell이 이미지를 로드하는 방식을 다시 가져오기로 했습니다. 관련 PR
  • URLString을 받아오면 각 Cell이 이미지를 로드하는 방식이 합리적인 방법이라고 느껴졌습니다.
    // 각 셀에서 일어나는 일들
    func configure(channel: Channel) {
        loadAsyncImage(with: channel.thumbnailImageURLString)
        self.titleLabel.text = channel.name
        self.descriptionLabel.text = channel.owner + (channel.description.isEmpty ? "" : " • \(channel.description)")
    }

    private func loadAsyncImage(with imageURLString: String) {
        guard let url = URL(string: imageURLString) else { return }
        URLSession.shared.dataTask(with: url) { [weak self] data, _, error in
            guard error == nil,
                  let data else { return }
            DispatchQueue.main.async {
                self?.thumbnailView.configure(with: UIImage(data: data))
            }
        }.resume()
    }

👀 새로 생긴 고민 상황

  • applySnapshotUsingReloadData를 살펴보면 당연하게도 without computing a diff or animating the changes 라는 말이 있었습니다.
  • reloadData()와 똑같이 작동하는 듯 보였습니다...

🤔 잠깐만... apply와 차이를 보면 성능에 큰 영향이 있을까?

  • 가장 궁금했던건 얼마나 성능 차이가 날까? 라는 궁금증이었습니다. 왜냐하면 applySnapshotUsingReloadData의 경우 Reset UI를 한다는 이야기가 있어 콜렉션뷰를 다시 그린다고 이해했기 때문에 리소스 차이가 얼마나 클까 하는 궁금증 이었습니다.
  • 방송을 2개 띄운 후 테스트를 진행해봤습니다.
  • CPU: 아무래도 image를 다시 받아오니까 CPU 사용량이 많을 수 밖에 없습니다. 51% → 58%
apply applySnapshotUsingReloadData
  • 메모리: 약 1.50% 증가했습니다. 이미지를 받아오고 새로 로드하는 과정 + UI를 다시 그리는 과정에서 차이가 있는 것 같습니다.
apply applySnapshotUsingReloadData
  • 네트워크: 당연히 바뀐 썸네일 이미지를 받아와야 하니까 네트워크가 주기적으로 쓰이네요.
apply applySnapshotUsingReloadData
  • 결론: 이미지를 새로 로드하는 것 정도 차이가 난다...? 어메이징하게 크게 차이는 나지 않는다...?

🥹 DiffableDataSource의 의미가 퇴색되었다.

  • 부드러운 애니메이션... 은 고사하고, DiffableDataSource를 활용하여 이미 만들어진 셀을 재사용하면서 변경된 데이터만 업데이트하고 싶었는데... 이미지를 변경해야 하기 때문에 모든 셀을 다시 그려야하는 방식인 applySnapshotUsingReloadData를 사용한 순간 DiffableDataSource 왜 쓰지? 라는 생각이 들었습니다.
  • 제가 원하는 방향은 이미지가 바뀔 때에만 apply snapshot을 하고 싶었습니다. 그렇게 된다면 셀을 업데이트 할때 바뀐 썸네일만 다시 그리니까 이미지를 다시 그리는 리소스도 줄어들 것이라고 생각했습니다.
  • Building High-Performance Lists and Collection Views...라는 멋진 것을 발견했지만... 딥다이브하다가 실패했습니다 🥹 우선 중복 코드만 개선했습니다...

관련 공식 문서
관련 WWDC영상