RLMArray has been invalidated or the containing object has been deleted, even with observer!

Hi , I did ask on Github but I don’t get any response
so I decided to ask here.

Goals

The goal is to delete object with its List data and update the Tableview!

Expected Results

Update the tableview without crash

Actual Results

Terminating app due to uncaught exception ‘RLMException’, reason: ‘RLMArray has been invalidated or the containing object has been deleted.’
*** First throw call stack:
(
0 CoreFoundation 0x00007fff23c4f02e __exceptionPreprocess + 350
1 libobjc.A.dylib 0x00007fff50b97b20 objc_exception_throw + 48
2 Realm 0x00000001021f5e97 _ZL10throwErrorP15RLMManagedArrayP8NSString + 311
3 Realm 0x00000001021f105a _ZL15translateErrorsIZ24-[RLMManagedArray count]E3$0EDaOT + 74
4 Realm 0x00000001021f1001 -[RLMManagedArray count] + 33
5 RealmSwift 0x00000001039b0e47 $s10RealmSwift8ListBaseC5countSivg + 103
6 AdministrativeContacts 0x0000000100f020a0 $s22AdministrativeContacts25AttachmentsViewControllerC05tableD0_21numberOfRowsInSectionSiSo07UITableD0C_SitF + 272
7 AdministrativeContacts 0x0000000100f021ac $s22AdministrativeContacts25AttachmentsViewControllerC05tableD0_21numberOfRowsInSectionSiSo07UITableD0C_SitFTo + 76
8 UIKitCore 0x00007fff47a607a1 -[UITableView numberOfRowsInSection:] + 62
9 UIKitCore 0x00007fff47a7163d -[UISectionRowData refreshWithSection:tableView:tableViewRowData:] + 1938
10 UIKitCore 0x00007fff47a73d1d -[UITableViewRowData ensureAllSectionsAreValid] + 102
11 UIKitCore 0x00007fff47a16ded -[UITableView endCellAnimationsWithContext:] + 3857
12 UIKitCore 0x00007fff47a34037 -[UITableView endUpdatesWithContext:] + 112
13 DZNEmptyDataSet 0x0000000101ca29ac dzn_original_implementation + 252
14 AdministrativeContacts 0x0000000100ef9db7 $s22AdministrativeContacts25AttachmentsViewControllerC011updateTableD7ResultsyyFy10RealmSwift0I16CollectionChangeOyAE4ListCyAA0C0CGGcfU
+ 1799
15 RealmSwift 0x00000001039b5491 $s10RealmSwift4ListC7observeySo20RLMNotificationTokenCyAA0A16CollectionChangeOyACyxGGcFySo8RLMArrayCyyXlGSg_So013RLMCollectionH0CSgs5Error_pSgtcfU
+ 321
16 RealmSwift 0x00000001039b55d5 $sSo8RLMArrayCyyXlGSgSo19RLMCollectionChangeCSgs5Error_pSgIegggg_AdGSo7NSErrorCSgIeyByyy_TR + 165
17 Realm 0x00000001021e4e01 ZZ23RLMAddNotificationBlockIN5realm4ListEEP20RLMNotificationTokenP11objc_objectRT_U13block_pointerFvS5_P19RLMCollectionChangeP7NSErrorEbENKUlRKNS0_19CollectionChangeSetESt13exception_ptrE_clESG_SH + 705
18 Realm 0x00000001021e4955 ZN5realm24CollectionChangeCallback4ImplIZ23RLMAddNotificationBlockINS_4ListEEP20RLMNotificationTokenP11objc_objectRT_U13block_pointerFvS7_P19RLMCollectionChangeP7NSErrorEbEUlRKNS_19CollectionChangeSetESt13exception_ptrE_E5afterESI + 69
19 Realm 0x000000010209e68e _ZN5realm24CollectionChangeCallback5afterERKNS_19CollectionChangeSetE + 46
20 Realm 0x000000010209e5e9 _ZZN5realm5_impl18CollectionNotifier13after_advanceEvENK3$9clINSt3__111unique_lockINS4_5mutexEEENS1_8CallbackEEEDaRT_RT0 + 169
21 Realm 0x00000001020876d6 _ZN5realm5_impl18CollectionNotifier17for_each_callbackIZNS1_13after_advanceEvE3$9EEvOT + 166
22 Realm 0x0000000102087629 _ZN5realm5_impl18CollectionNotifier13after_advanceEv + 25
23 Realm 0x00000001021509d8 _ZN5realm5_impl16RealmCoordinator23process_available_asyncERNS_5RealmE + 1704
24 Realm 0x00000001023d7e0d _ZN5realm5Realm6notifyEv + 397
25 Realm 0x00000001024c3250 _ZNK5realm5_impl17WeakRealmNotifier8CallbackclEv + 64
26 Realm 0x00000001024c63fc ZZN5realm4util15EventLoopSignalINS_5_impl17WeakRealmNotifier8CallbackEEC1EOS4_ENKUlPvE_clES7 + 28
27 Realm 0x00000001024c63d5 ZZN5realm4util15EventLoopSignalINS_5_impl17WeakRealmNotifier8CallbackEEC1EOS4_ENUlPvE_8__invokeES7 + 21
28 CoreFoundation 0x00007fff23bb2221 CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION + 17
29 CoreFoundation 0x00007fff23bb214c __CFRunLoopDoSource0 + 76
30 CoreFoundation 0x00007fff23bb197c __CFRunLoopDoSources0 + 268
31 CoreFoundation 0x00007fff23bac62f __CFRunLoopRun + 1263
32 CoreFoundation 0x00007fff23babe16 CFRunLoopRunSpecific + 438
33 GraphicsServices 0x00007fff38438bb0 GSEventRunModal + 65
34 UIKitCore 0x00007fff4784fb48 UIApplicationMain + 1621
35 AdministrativeContacts 0x00000001010cf62b main + 75
36 libdyld.dylib 0x00007fff51a1dc25 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

Steps to Reproduce

I notced that the crash happend after rearch to tableView.endUpdates()

Provide a code sample or test case that highlights the issue.

on current viewController I have

var attachmentsDataArray : List<Attachments>?

on viewLoad() I have this function

  func updateTableViewResults() {
        do {

           let realm = try Realm(configuration: RealmHelper.shared.RealmConfiguration(realmType: .SavedTransactions))
        
           guard let documentNumber = documentNumber else {
                         print("AttachmentsViewController readRealm: documentNumber is nil")
                         return}
                     
                     guard let copyNumber = copyNumber else {
                         print("AttachmentsViewController readRealm: copyNumber is nil")
                         return}

                     let openedDocumentsList = realm.objects(OpenedDocumentsList.self)
        
        self.attachmentsDataArray = openedDocumentsList.filter("documentNumber == %@ AND CopyNumber == %@" , documentNumber ,copyNumber).first?.attachmentList
        

            notificationAttachmentToken = attachmentsDataArray?.observe { [weak self] (changes: RealmCollectionChange) in
               guard let tableView = self?.attachmentsTableview else { return }
               switch changes {
               case .initial:
                self?.reloadTableView()
                break
               case .update(_, let deletions, let insertions, let modifications):
                   tableView.beginUpdates()
                   tableView.insertRows(at: insertions.map { IndexPath(row: $0, section: 0) }, with: .automatic)
                   tableView.deleteRows(at: deletions.map { IndexPath(row: $0, section: 0) }, with: .automatic)
                   tableView.reloadRows(at: modifications.map { IndexPath(row: $0, section: 0) }, with: .automatic)

                   tableView.endUpdates()

                   break
               case .error(let error):
                   print("Error: \(error)")
                   break
               }
           }
            }catch{
                       print("realm Error: \(error)")
                   }
       }

on delete :
1st I did try delete it manually then I use his code

both way I got same crash !
so I’m sure the issue not on delete function itself

this is my delete function

  func deleteRealmObjectByDocumentNumber(documentNumber:String,copyNumber:Int){
       do {
           let realm = try Realm(configuration: RealmHelper
               .shared.RealmConfiguration(realmType: .SavedTransactions))
           
          let receivedDocumentsDataResult = realm.objects(OpenedDocumentsList.self)

               let parentObject = receivedDocumentsDataResult.filter("documentNumber == %@ && CopyNumber == %@",documentNumber,copyNumber).first
           

           if let  parentObject = parentObject {
               
               try realm.write {
                   realm.delete(parentObject, cascading: true)

               }
           }
 
       }catch {
           print("there is error with delete Realm object ! : \(error)")
       }
   }

I did on Realm Studio and I notice that the object and its List deleted successfully but on tableview I don’t noticed it removed

Version of Realm and Tooling

Realm framework version: ?
Realm Swift
4.3.0
Realm Object Server version: ?

Xcode version: ?
11.2.1

iOS/OSX version: ?
10.15.2

Dependency manager + version: ?
cocoapods-1.8.4

The code in the question is somewhat disjointed so it’s hard to know what’s going on. I see you’re getting a subset of realm results with

let openedDocumentsList = realm.objects(OpenedDocumentsList.self)
self.attachmentsDataArray = openedDocumentsList
      .filter("documentNumber == %@ AND CopyNumber == %@", documentNumber, copyNumber)
      .first?
      .attachmentList

and then observing those results for changes

notificationAttachmentToken = attachmentsDataArray?.observe

but the delete function is referring back to the this object OpenedDocumentsList.self with

let receivedDocumentsDataResult = realm.objects(OpenedDocumentsList.self)

so it’s unclear what self.attachmentsDataArray has to do with the delete? Since it’s observing the the first attachmentList only. Meaning that only changes within that specific list will fire the observe event.

.first?.attachmentList

Why is that in the question?

It’s also not stated which line is crashing and since you’re using third party code, did you remove that code and see if it still crashes? Comment out realm.delete(parentObject, cascading: true) and see what happens.

Also, what is this? OpenedDocumentsList.self

Just a minor point, using the same name for a class or struct and a local var, while legal with capitalization, makes the code hard to read - upper case O vs lower case o is probably not a good idea for readability.

Thank you for your answer and suggestion to improve my code readability

I noticed the confusing you have when you are reading my code.

openedDocumentsList is the List that I use on previous Tableview, that why I get only the first item
(I will move this to prepareForSegue function it will be clear this way)

self.attachmentsDataArray is the array I used on current Tableview

I did remove realm.delete(parentObject, cascading: true)
and change the code to delete it manually

so the code now became like this

  func deleteRealmObjectByDocumentNumber(documentNumber:String,copyNumber:Int){
        do {
            let realm = try Realm(configuration: RealmHelper
                .shared.RealmConfiguration(realmType: .SavedTransactions))
            
           let receivedDocumentsDataResult = realm.objects(OpenedDocumentsList.self)

                let parentObject = receivedDocumentsDataResult.filter("documentNumber == %@ && CopyNumber == %@",documentNumber,copyNumber).first
            

            if let childObject = parentObject?.attachmentList {
                
                for index in childObject {
                    deleteObject(realm: realm, ObjectToDelete: index)
                }
                
                if let  parentObject = parentObject {
                    deleteObject(realm: realm, ObjectToDelete: parentObject)
                }
            }

        }catch {
            print("there is error with delete Realm object ! : \(error)")
        }
    }

The result is the Tableview updated successfully by removing cells and updating the Tableview content (become empty). Also, the crash logs did change. Then I noticed that there was an issue on previous ViewController, I was deleting other Realm Data again!
After removing it, the code works fine!

All these issues happened because I was adding Offline feature after a long time
so I did add some code before but change it now

Yeah! Great post. I have Office setup.