-
반응형
Swift Combine 잘못 사용하다가 크래시 났던 케이스를 정리합니다.
문제
List에서 item 삭제 시 아래와 같은 에러로 크래시
crash: Object has been deleted or invalidated." 0x0000600000c45140
crash: Object has been deleted or invalidated." 0x0000600000c45140
상황
ContentView 에서 viewModel 안에 있는 recordingList를 참조하고 있고, cell 도 동시에 viewModel 를 참조하고 있는 상황
// ContentView.swift@ObservedObject var viewModel = RecorderViewModel()ForEach(viewModel.recordingsList, id: \.id) { item inRecordingCell(audioPlayer: audioPlayer, item: item, viewModel: viewModel)}// RecordingCell.swift@ObservedObject var viewModel: RecorderViewModel// RecorderViewModel.swiftclass RecorderViewModel: ObservableObject {@Published var recordingsList: [DBRecordingItem] = []init() {let allRecordings = try! DBService.shared.allRecordingsSortedByCreatedAt()RealmPublishers.array(from: allRecordings).sink(receiveCompletion: { _ in}, receiveValue: { recordings inprint("DB has changed to: \(recordings.map(\.title))")self.recordingsList = recordings}).store(in: &subscriptions)}}문제
ContentView의 List와 Cell이 동시에 RecorderViewModel을 Observing하고 있기 때문에 viewmodel의 recordingsList 가 변경되었을 때 두번씩 호출되는 현상이 있었다. Realm에 추가될때는 크게 문제가 되지 않았지만 delete 하는 경우에 이미 삭제된 realm item에 접근하게 되면서 크래시가 발생했다.
해결
1번처럼 되어있던 것을 2번으로 바꿔줌으로서 해결
더이상 recordingList를 참조하지 않고 viewModel에서 함수만 가져다 사용할 수 있게 되었다.
// RecordingCell.swift1. @ObservedObject var viewModel: RecorderViewModel2. var viewModel: RecorderViewModel+
위에서 문제를 해결한 줄 알았지만 Realm Item을 직접 가지고 다니면서 cell에 DBItem 레퍼런스를 자꾸 주다보니 예상치 못한 곳에서 자꾸 이미 삭제된 DBItem을 호출하는 경우가 생겼다.
결국 Source of truth는 DB로 하되, DB가 바뀔 때 마다 그걸 UI 용 model로 변경해서 list에 넣어주는 식으로 변경했다.
// RecorderViewModel.swiftclass RecorderViewModel: ObservableObject {//AS-IS@Published var recordingsList: [DBRecordingItem] = []// TO-BE@Published var recordingsList: [RecordingItem] = []init() {let allRecordings = try! DBService.shared.allRecordingsSortedByCreatedAt()RealmPublishers.array(from: allRecordings).sink(receiveCompletion: { _ in}, receiveValue: { recordings inprint("DB has changed to: \(recordings.map(\.title))")// AS-ISself.recordingsList = recordings// TO-BEself.recordingList = recordings.map { $0.createRecordingItem() }}).store(in: &subscriptions)}}반응형'개발' 카테고리의 다른 글
Ruby path 다시 설정하기 (0) 2020.11.30 [Xcode] Device Build, Archive 안되는 이슈 CodeSign error: unknown error -26276 해결 방법 (0) 2020.11.27 Jekyll 설치하기 (0) 2020.11.11 Swift Code snippet (0) 2020.11.06 SwiftUI Code snippet - 내가 보려고 정리하는 코드 (0) 2020.11.06