티스토리 뷰

반응형

 

Diffable Data Source in iOS 15  에서 다룬 내용인데, 헷갈리니까 한번 더 정리!


 

[1] UITableViewDiffableDataSource의 4가지 apply 메서드들

 

UITableViewDiffableDataSource 에는 Updating Data를 위한 4개의 apply 메서드들이 있습니다.

 

 

위에서부터 적어보면 다음과 같습니다. 

 

- apply(_:animatingDifferences:)  // iOS 15+

- apply(_:animatingDifferences:completion:)  // iOS 13+

- applySnapshotUsingReloadData(_:)   // iOS 15+

- applySnapshotUsingReloadData(_:completion:) // iOS 15+

 

 

[2] 각각 살펴보기 

 

4개 중, 하나만 iOS 13부터 쓸 수 있으므로 이것을 먼저 살펴보겠습니다.

 

[2.1]  apply(_:animatingDifferences:completion:)  

 

# 문서 

✔️ snapshot의 데이터 상태를 반영하도록 UI를 업데이트한다. 

✔️ animatingDifferences가 true면 테이블뷰를 에니메이팅하며 업데이트하고 false면 애니메이션 안한다. 

✔️ 업데이트가 끝나면 completion handler가 실행된다. 시스템은 이 클로저를 main queue에서 콜한다.

 

 

✔️ diffable data source는 tableview의 current state와 new state를 차이(diff) 를 계산하는데, 이것은  O(n)의 시간복잡도를 가진다. (n은 snapshot에 있는 item 갯수) 

✔️ background queue에서 이 메소드를 콜해도 안전하지만, 항상 main queue에서 부르던가 background queue에서 부르던가 하나만 하라. 

 

 

# 예제

 

간단히 예제를 작성해보겠습니다. 

 

 

돌려보면 아래와 같고 

 

콘솔 출력은 이렇게 됩니다. 

// print
applyInitialSnapshot() completion called
applyNewSnapshot() completion called

 

그럼 똑같은 snapshot을 apply해도 completion이 불릴까요?

맞습니다! 이렇게 바꿔서 돌려봐도 

    func applyNewSnapshot() {
        dataSource.apply(dataSource.snapshot(), animatingDifferences: true) {
            print(#function + " completion called")
        }
    }

 

똑같이 출력되는 것을 볼 수 있습니다. 

// print
applyInitialSnapshot() completion called
applyNewSnapshot() completion called

 

 

[2.2] apply(_:animatingDifferences:)  

이제부터 iOS 15 부터 쓸 수 있는 apply 메서드들을 살펴보겠습니다. 

 

# 문서 

위의 메서드와 다른 점은 completion이라는 파라미터가 빠지고 뒤에 async가 붙었다는 점입니다. 

문서에 별도 설명은 없습니다. 

 

애플이 왜 iOS 15에 이것을 추가했을까요?

그 이유는 WWDC 2021 > Make blazing fast lists and collection views 에서 알 수 있습니다. 

 

위에서 살펴본 apply(_:animatingDifferences:completion:)는 

모든 경우, 이전 snapshot과 변경된 snapshot을 비교해서 diff만 업데이트하는게 아닙니다!!! 

animatingDifferences에 어떤 값을 넘겨주는 가에 따라서 다르게 동작합니다.  

1) animatingDifferences 파라미터에 true를 넘기면 diff만 딱 업데이트. 
2) animatingDifferences 파라미터에 false를 넘기면 내부적으로 reloadData로 바뀌어서 동작.

 

 

즉 animatingDifferences에 true를 넘겨야지만 diff만 딱 업데이트합니다.

근데 이거 예측하기 너무 어렵지 않나요....?... 

 

 

그래서인지..  애플은

iOS 15에서는 animatingDifferences 값과 상관없이

오직 difference만 적용하고 다른 extra work는 하지 않는 API를 추가했다고 합니다.

 

 

정리하자면.. 

✔️ apply(_:animatingDifferences:completion:)  // iOS 13
    => animatingDifferences가 true일때만 diff만 업데이트. false면 reloadData로 동작. 

 

✔️ apply(_:animatingDifferences:)  // iOS 15
   => animatingDifferences에 상관없이 항상 diff만 업데이트. 

       

 

great performance 를 위해 apply(_:animatingDifferences:)  를 쓰는 게 더 좋습니다. 

이를 위해 별도 코드수정 작업을 해줘야하는 것이 아니라  iOS 15에서 알아서 됩니다. 

 

 

왜냐면.. 

apply(_:animatingDifferences:completion:) 의 completion 디폴트 값이 nil로 되어있기 때문에

아래와 같이 코드를 작성하면  두개의 함수 시그니처가 같으므로

dataSource.apply(snapshot, animatingDifferences: true)

iOS 13, 14에서는 apply(_:animatingDifferences:completion:) 로 불리고

iOS 15에서는 apply(_:animatingDifferences:) 로 불립니다. 

실제 시뮬레이터 버전을 다르게 해서 돌려보면 

iOS 13,14 와 iOS 15가 다르게 동작하는 것을 확인하실 수 있습니다. 

 

 

 

[2.3]  applySnapshotUsingReloadData(_:)   

 

# 문서 

 

 

✔️ diff를 계산하지 않고 reloadData한다.

(위의 맥락과 이어집니다.

apply가 diff만 업데이트하도록 바뀌었기때문에 reload를 하고 싶을때를 위한 메서드를 제공해줬습니다. 

diff만 업데이트 하는게 아니라 reload 를 하고 싶은면 이 메소드를 콜해주면 됩니다.) 

 

 

✔️ 시스템은 진행 중인 모든 아이템 애니메이션을 중단하고 테이블뷰를 즉시 다시 reload 한다.  

 

 

✔️ background queue에서 이 메소드를 콜해도 안전하지만, 항상 main queue에서 부르던가 background queue에서 부르던가 하나만 하라. 

 

 

 

[2.4] applySnapshotUsingReloadData(_:completion:) 

 

# 문서 

 

 

applySnapshotUsingReloadData(_:)  과 똑같은데 completion 파라미터만 추가적으로 있는 것입니다.

시스템은  completion 클로저를 main queue에서 콜합니다.

 

 

 

 

 

 

반응형
댓글