Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

cchanmi

[iOS] UIKit+Combine 환경에서 CollectionView Cell 바인딩 문제 해결 본문

iOS

[iOS] UIKit+Combine 환경에서 CollectionView Cell 바인딩 문제 해결

cchanmi 2024. 9. 7. 18:06

ViewModel로부터 관찰한 데이터를 sink 클로저 안에서 CollectionView에 바인딩을 해야 했습니다.

output.totalHasMyPlanResult
    .receive(on: DispatchQueue.main)
    .sink { [weak self] response in
        print("collectionView에 바인딩 될 데이터: ", response)
    }
    .store(in: &cancelBag)


MVVM 원칙에 따라 View가 Data를 알 필요가 없었기 때문에, 해당 데이터를 전역으로 추가하여 외부 CollectionViewDatasource 메서드에서 바인딩 할 수 없었던 상황이었습니다.

생각나는 방안으로는 2가지가 있었습니다.
1) CollectionViewDiffableDatasource를 사용하기
2) 직접 CollectionViewDatasource를 구현하기

func setUpDataSource() {
    dataSource = UICollectionViewDiffableDataSource(collectionView: collectionView, cellProvider: { (collectionView, indexPath, card) -> UICollectionViewCell? in
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ExampleCell", for: indexPath) as! ExampleCell
        return cell
    })
}

 


1번 방법을 사용하면 cellProvider 클로저를 통해 collectionView의 cell에 접근할 수 있었지만, 현재 뷰에서는 데이터의 변동이 없고, 다이나믹한 애니메이션 처리가 필요하지 않았기 때문에 DiffableDatasource를 도입할 필요는 없다고 생각했습니다.

그런 이유로 2번 방법으로 택했고, 직접 CollectionViewDatasource 구현하여 바인딩을 해 주어 해결했습니다.
전역으로 해당 CollectionViewDatasource를 선언만 해 두고, sink 클로저 내에서 해당 CollectionView에 맞는 데이터를 초기화 시에 주입해 주었습니다.

 

// 전역으로 선언
private var mySmeemDataSource: MySmeemCollectionViewDataSource!

output.totalHasMyPlanResult
    .receive(on: DispatchQueue.main)
    .sink { [weak self] response in
        self?.mySmeemDataSource = MySmeemCollectionViewDataSource(numberItems: response.mySummaryNumber,
                                                                  textItems: response.mySumamryText)
        self?.mySmeemCollectionView.dataSource = self?.mySmeemDataSource
        self?.mySmeemCollectionView.reloadData()
    }
    .store(in: &cancelBag)

 

 


 

아쉬운 점

1. Datasource가 데이터를 알게 되는 상황

final class MySmeemCollectionViewDataSource: NSObject, UICollectionViewDataSource {
    
    private let numberItems: [Int]
    private let textItems: [String]
    
    init(numberItems: [Int], textItems: [String]) {
        self.numberItems = numberItems
        self.textItems = textItems
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(cellType: MySmeemCollectionViewCell.self, indexPath: indexPath)
        cell.setNumberData(number: self.numberItems[indexPath.item])
        cell.setTextData(text: self.textItems[indexPath.item])
        return cell
    }
}

 

Datasource 초기화 시에 데이터를 주입해 준 이후 바인딩은 collectionView 메서드에서 일어나기 때문에, 전역으로 데이터를 가지고 있어야 하는 상황이 발생했습니다.
MVVM 원칙을 따르기 위해 해당 방안을 도입한 것이었는데, 결국에은 ViewController가 아닌 Datasource가 데이터의 책임에 갖게 되어서 아쉬움이 남았습니다.
꼭 다이나믹한 데이터 바인딩이나 애니메이션 처리가 중요한 상황이 아니더라도, MVVM 원칙을 지키기 위해 DiffableDatasource를 도입하는 것도 하나의 이유가 될 수 있겠다는 생각이 들었습니다.

Comments