Search code examples
realmrealm-mobile-platform

Realm Swfit Async Write Method


I am new with swift concurrency especially Realm Swift. I have 2 sample codes where i think are the same, but it won't work

Below is the example of not working code

var localRealm: Realm {
    get {
        return try! Realm()
    }
}
fileprivate func testAsyncRealm() {
    self.localRealm.beginAsyncWrite {
        self.localRealm.create(SwiftStringObject.self, value: ["string2"])
        self.localRealm.commitAsyncWrite(allowGrouping: true) { error in
            print(error)
        }
    }
}

This code will throw exception Terminating app due to uncaught exception 'RLMException', reason: Can only add, remove, or create objects in a Realm in a write transaction - call beginWriteTransaction on an RLMRealm instance first.

However, below code will work without any problem

fileprivate func testAsyncRealm() {
    let realm = try! Realm()
    realm.beginAsyncWrite {
        realm.create(SwiftStringObject.self, value: ["string2"])
        realm.commitAsyncWrite(allowGrouping: true) { error in
            print(error)
        }
    }
}

What am I missing here? Thanks...

Realm Version: 10.40.0


Solution

  • This is just a theory but fits the issue

    When a realm object begins an async write transaction, it appears a flag is set on that realm isPerformingAsynchronousWriteOperations to indicate it's in an async write. For example

    var realm = try! Realm()
            
    realm.beginAsyncWrite {
       let isWrite = realm.isPerformingAsynchronousWriteOperations
       print("is write? \(isWrite)") //outputs true
    }
    

    However, in your code (abbreviated)

    var localRealm: Realm {
        get {
            return try! Realm()
        }
    }
    fileprivate func testAsyncRealm() {
        self.localRealm.beginAsyncWrite {
           let isWrite = self.localRealm.isPerformingAsynchronousWriteOperations
           print("is write? \(isWrite)") //outputs false
        }
    }
    

    the output is false - indicating that the flag was not set so Realm doesn't think its in an asynch write.

    I'll propose the behavior is because each time the var is accessed via self.localRealm, it re-initializes Realm, with that flag being false.

    The simple solution is to work with the same instance of Realm without re-initializing it

    fileprivate func doAsyncWrite() {
       var realm = self.localRealm  //gets a realm instance
            
       realm.beginAsyncWrite { //use that same realm to write, which sets the flag
          let isWrite = realm.isPerformingAsynchronousWriteOperations
          print("is write? \(isWrite)") //returns true
       }
    }
    

    With that change, the code in the question works correctly.