ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Error] Diffable Datasource 사용중 겪은 여러 에러 해결
    카테고리 없음 2024. 8. 26. 18:02

     

    does not conform to protocol 'Equatable'

    Diffable Datasource의 section 과 item 을 구성 하려면 Hashable 준수를 해야하는데

    Associated Value Enum의 경우 Hashable를 준수 하지 않음 따로 넣어줘야함 근데 전달 하고자 하는 값

    ex> tag item, faq item

    이 struct 형태가 아니라 protocol 을 사용하여 넘겨주고 있음 여기서 에러 발생

    protocol 이 Hashable를 준수 했음에도 에러는 여전히 발생함

    public enum FAQSectionItem: Hashable {
       
       case tag(tag: any FAQTagDisplayable, isSelected: Bool)
        case faq(item: any FAQItemDisplayable, isCollapsed: Bool)
    }
    
    //Type 'FAQSectionItem' does not conform to protocol 'Equatable'

    그래서 hash(into) 와 == 함수를 구현 해줘야함 Equatable 이 꼭 있어야 하는 함수임

    ic enum FAQSectionItem: Hashable {
    
        case tag(tag: any FAQTagDisplayable, isSelected: Bool)
        case faq(item: any FAQItemDisplayable)
        
        public func hash(into hasher: inout Hasher) {
            switch self {
            case let .faq(item): hasher.combine(item)
            case let .tag(tag, isSelected): hasher.combine(tag)
            }
        }
        public static func == (lhs: FAQSectionItem, rhs: FAQSectionItem) -> Bool {
            switch (lhs, rhs) {
            case let (.tag(lhstag, _), .tag(rhstag, _)):
                return lhstag.id == rhstag.id
            case let (.faq(lhsItem), .faq(rhsItem)):
                return lhsItem.id == rhsItem.id
            default: return false
            }
        }
    }
    
    

    hasher 에 고유값인 item 을 combine 하여 특수한 hash 값을 가지도록 하는것임

    == 은 해당 값들을 비교하기 위해 고유값 (item의 id)을 직접 비교하도록 하여서 구현 함

     

    Apply 이후 cell provider 가 동작안함

     

     viewModel.snapshot.bind { [weak self] snapshot in
                self?.diffableDataSource?.apply(snapshot, animatingDifferences: true)
            }.disposed(by: disposeBag)
    

    tag 를 눌러 API 요청후 새로운 리스트를 사용하여 변경시킨 경우 cell provider가 호출이 되었으나

    expand toggle 같은 국소적 변경에는 cell provider가 호출 되지 않음

    둘다 apply 함수는 호출 되었음은 확인함

    문제는 여기에 있었다.

      
      public static func == (lhs: FAQSectionItem, rhs: FAQSectionItem) -> Bool {
            switch (lhs, rhs) {
            case let (.tag(lhstag, _), .tag(rhstag, _)):
                return lhstag.id == rhstag.id
            case let (.faq(lhsItem), .faq(rhsItem)):
                return lhsItem.id == rhsItem.id
            default: return false
            }
        }
      
      
    

    tag값 item 값만 비교하니까 selected 값이 바뀌어도 item의 id가 바뀌지 않으면

    같은 item 으로 취급 되어 불리지 않았음

    item 이 변경된 사실을 알려줘야함 and 연산으로 selected 정보를 넘겨 주던지 아니면

    false 를 리턴하여 무조건 업데이트 하도록 수정

    public static func == (lhs: FAQCellData, rhs: FAQCellData) -> Bool {
            switch (lhs, rhs) {
            case let (.tag(lhsTag, lhsSelected), .tag(rhsTag, rhsSelected)):
                return lhsTag.id == rhsTag.id && lhsSelected == rhsSelected
            case let (.faq(lhsItem, lhsSelected), .faq(rhsItem, rhsSelected)):
                return lhsItem.id == rhsItem.id && lhsSelected == rhsSelected
            default: return false
            }
        }
    

    hashable 함수를 대충 작성해도 동작에 문제는 없음을 확인했다

     public func hash(into hasher: inout Hasher) { 
     
     }
         
    public static func == (lhs: FAQCellData, rhs: FAQCellData) -> Bool {
    	 return false
    }
        
    

    그런데 이러면 올바른 해시값을 가지고 있지 않으므로 해시테이블의 시간복잡도 장점을 못가져가는것 같다.

    그래서 직접 넣어주었음

     

     

    snapshot apply 하면 데이터가 바뀌면서 collection view의 스크롤이 가장 상단에 위치해버림

    그래서 동작에 좀 어색함이 있었다.

    이유는 모르겠으나 snapshot이 새로 업데이트 되면서 무조건 올라가는게 디폴트 동작인듯하다

    set contentoffset 으로 방어하였다.

    viewModel.snapshot.bind { [weak self] snapshot in
                let currentOffset = self?.collectionView.contentOffset
    
                self?.diffableDataSource?.apply(snapshot, animatingDifferences: false)
                if let currentOffset = currentOffset {
                    self?.collectionView.setContentOffset(currentOffset, animated: false)
                }
            }.disposed(by: disposeBag)
    

    댓글

Designed by Tistory.