본문 바로가기
iOS/Issue

[Error] object has been deleted or invalidated.

by Callie_ 2023. 11. 1.

 

 

⚙️ 환경

- iOS 16이상
- Swift 5.9
- Xcode 15
 

💻 문제상황 

- 개인앱 프로젝트 진행 중 diffableDatasource로 컬렉션뷰 활용하는 UI를 사용 중이었고, Realm에서 create는 잘 되는데 delete를 하려고 하면 delete 팝업창에서 앱이 터지며 'object has been deleted or invalidate'라는 오류가 CollectionView가 있는 VC의 snapshot을 찍는 부분에서 났다.
- '이미 삭제된 개체인데 왜 접근해?' 의미의 오류였는데, 객체가 한 개일 땐 문제없이 구현이 되었으나 두 개 이상부터는 삭제 시 위와 같은 오류 뜨며 앱이 멈췄다. 
 

✏️해결방안

- 처음엔 realm과 관련된 문제인 줄 알고 realm을 사용한 코드를 모두 확인해보았으나, (1) 삭제할 때 오류가 나며 앱이 멈춤에도 불구하고 렘에서는 삭제 메서드를 실행한 셀 및 데이터가 삭제되고 있었고 (2) print를 찍어서 확인했을 때도 메서드에 문제 없음을 확인했기 때문에 내 예상과 달리 realm의 문제가 아니었다.
 
- 간단하게 정리하자면 diffableDatasource부분에서 오류가 찍히고 있었기 때문에 diffableDatasource 중 업데이트(apply)를 해주는 부분의 문제였다. diffableDatasource를 사용할 경우 reloadData의 역할을 snapshot이 대신하는데 apply의 종류 문제였다는 걸 해당 문제로 일주일동안 앓다가 멘토님의 해결방안을 보며 배우게 되었다. 오류가 찍히는 부분도 딱 셀의 개수를 삭제 이후의 개수로 업데이트 해주는 메서드로 이어질 때 앱이 터졌기 때문에 완전히 apply의 사용이 문제가 맞았다.
 
- 내가 diffableDatasource를 프로젝트에 사용하게 된 계기는 diffableDatasource의 animation 효과 때문이었다. 그런데 이 애니메이션 효과를 쓰는 apply (animationDifferences: True)를 사용한 스냅샷은 새로 업데이트 되기 전 셀 위치를 기억하고, 그 위치에서 업데이트를 해준다. 그래서 객체를 삭제해버리면 스냅샷에는 여전히 해당 객체가 존재하는데 실제로는 삭제되었기 때문에 'object has been deleted or invalidate'라는 오류가 뜨고 있었던 것. 말그대로 삭제된 객체에 스냅샷은 그 객체를 업데이트 해주려고 접근하고 있기에 문제가 발생했던 거다.
 
- 수정한 코드:

 
- apply의 종류 중 applySnapshotUsingReloadData 라는 게 있었다. apply(snapshot) 부분을 applySnapshotUsingReloadData(snapshot)으로 수정하자, 접근 관련 오류가 해결되었다!
 
- applySnapshotUsingReloadData에 대하여 공식문서를 확인해보았다. 문서에는 Resets the UI to reflect the state of the data in the snapshot without computing a diff or animating the changes. 라고 정의를 해주고 있는데, applySnapshotUsingReloadData 메서드는 current state과 new state의 차이를 계산하거나 animating 변화의 영향을 받지 않고 스냅샷의 데이터 상태를 UI에 반영해주는 것이라고 한다. 그렇기 때문에 스냅샷은 이전에 기억하고 있었던 객체에 계산을 하기 위해 접근하려하지 않고 바로 업데이트 되는 데이터를 반영해줄 수 있게 된 것.
 
 
 

🧹DiffableDatasource + Snapshot + apply  간단하게 정리

* 모두 애플 공식 문서 내용 기반으로 정리함.
 
* DiffableDatasource: The object you use to manage data and provide cells for a collection view.

  • DiffableDatasource는 컬렉션뷰에 필요한 데이터를 관리하고 관련 UI를 변화를 스스로 추적해서 업데이트 한다.
  • Hashable Value로 데이터의 상태를 확인하여 데이터 변화를 추적한다. (CollectionView나 TableView를 그릴 때 누구나 한번쯤은 out of index 오류를 만나봤을 것이다. 그런 오류가 발생할 일을 방지할 수 있음! )

 

 
* Snapshot: a representation of the current state of the data in the colleciton view

  • Snapshot은 컬렉션뷰를 그리는 UI가 Truth인 데이터의 현재상태를 나타내는 역할을 한다. Truth하지 않다는 건 그 데이터가 더이상 유효하지 않거나, 비어있음을 의미한다.

* apply

  • apply 코드가 두 개가 있는데, 하나는 iOS 13에 등장 메서드, 다른 하나는 iOS 15에 등장한 메서드이다.
  • reloadData와 같은 역할은 하는데, iOS13에 등장한 apply는 animatingDiffrence가 true일 때만 diff 업데이트, false 일 때면 reloadData 수행 ||| iOS15에 등장한 apply는 animatingDiffrence에 상관없이 항상 diff만 업데이트를 해준다....인데 너무 어렵다.그런데 animation설정을 생각하면 iOS15에 등장한 apply를 쓰는게 좋지 않나.

* applySnapshotUsingReloadData

  • current state과 new state의 차이(diff)를 계산하거나 animating 변화의 영향을 받지 않고 스냅샷의 데이터 상태를 UI에 반영해주는 메서드. 조금 더 reload에 초점을 맞춘 것 같다.