-Today's Learning Content-

  • Identifier

1. RxDataSource 업데이트 에러

내용 정리

프로젝트 진행 중 셀의 정보를 업데이트 해도 UI가 업데이트 되지 않는 버그를 발견. 이를 해결하는 과정을 적어보자.

1) UI 버그 발견

이번 프로젝트에서는 RxDataSource를 사용해서 컬렉션뷰를 구현해 보았는데, 셀을 업데이트 해도 UI에 적용이 되지 않는 문제가 발생했다.
데이터 소스 코드는 아래와 같은데...

func makeDataSource() -> DataSource {
	return DataSource(configureCell: { [weak self] datasource, collectionView, indexPath, item in
		guard
			let self,
			let cell = collectionView.dequeueReusableCell(
					withReuseIdentifier: AlarmCollectionViewCell.id,
					for: indexPath
				) as? AlarmCollectionViewCell
			else { return .init() }
            
		cell.configCell(item.data)

	// ...
}

여기서 cell.configCell(_:)을 사용해서 셀의 UI를 업데이트 해줘야 하는데, 이 부분이 아예 호출도 되지 않았다.

혼자서 방법을 계속 연구하다가 결국 튜터님을 찾아갔는데 해결한 방법은 아래와 같다.

2) Identifier

RxDataSource로 컬렉션뷰를 구현할 때는 섹션 모델을 지정해 주어야 한다.
그래서 나도 새로 모델을 만들었는데,

/// 컬렉션뷰 데이터소스의 아이템 정의
struct AlarmItem: IdentifiableType, Hashable {
    typealias Identity = Int
    var identity: Identity {
        return self.hashValue
    }
    
    let data: Alarm
}

/// 컬렉션뷰 데이터소스의 섹션 정의
struct AlarmSectionModel: AnimatableSectionModelType {
    typealias Identity = String
    typealias Item = AlarmItem
    
    var identity: String {
        return String(describing: Self.self)
    }
    var items: [AlarmItem]
    
    init(items: [AlarmItem]) {
        self.items = items
    }
    
    init(original: AlarmSectionModel, items: [AlarmItem]) {
        self = original
        self.items = items
    }
}

여기서 문제는 AlarmItem의 identifier가 잘못되어 있었다.
알람 아이템의 identifier를 Int로 설정해서 self.hashValue로 설정했는데, 이 값이 셀을 재사용할 때마다 새로 생성되어 기존의 셀에 업데이트가 적용이 안 되는 버그가 있었다.

그래서 저 부분을 아래와 같이 바꿔주었다.

struct AlarmItem: IdentifiableType, Hashable {
    typealias Identity = UUID
    var identity: Identity {
        return UUID()
    }
    
    let data: Alarm
}

UUID를 사용해서 identifier를 지정해주니 셀의 고유 id가 생성되어 무사히 UI 업데이트가 이루어지는 것을 확인할 수 있었다.

그렇다면 왜 identifier가 달라진 것만으로 동작이 달라진걸까?

3) RxDataSource의 identifier

RxDataSource는 주로 Diffable Data Source 또는 내부적으로 Diff 알고리즘을 사용해 데이터를 관리한다.

또, RxDataSource는 identifier를 기준으로 데이터 변화를 계산해 컬렉션뷰의 삽입, 삭제, 수정 애니메이션을 수행하게 된다. 때문에 identifier가 없거나 고유하지 않으면 변경 사항을 정확히 추적하지 못해 전체 셀을 리로드하여 메모리가 낭비되는 문제가 발생할 수 있다.

컬렉션뷰의 UI와 데이터의 상태를 일관되게 유지하려면 각 아이템이 고유한 identifier를 가져야 한다.
왜냐하면, 만약 동일한 identifier를 가진 아이템이 중복되면 예기치 않은 동작이나 UI 버그가 발생할 수 있기 때문이다.

데이터가 변경될 때 RxDataSource는 identifier를 기준으로 변경 사항을 매핑하므로, 중복된 identifier는 오작동의 원인이 될 수 있다.

정리하자면, RxDataSource에서 identifier는 데이터와 UI의 상태를 동기화하고, 효율적이고 정확한 변경 감지를 위해 필수적이고 중요한 요소이다.

4) 결론

RxDataSource는 만들어두면 편하고 좋지만, 아직 공부가 더 필요할 것 같다... 섹션이 여러개일 경우라던지 아이템이 여러개일 경우라던지... 자주 사용해보면서 익혀보도록 하자.


-Today's Lesson Review-

identifier가 이렇게 중요한 줄 몰랐다...
profile
이유있는 코드를 쓰자!!

0개의 댓글