RealmSwift RLMException
Asked Answered
M

2

8

I am using RealmSwift for my project. However, I'm not sure how to tackle the following:

RMLException: Attempting to modify object outside of a write transaction - call beginWriteTransaction on an RLMRealm instance first

thrown.

Anyone any clue?

import RealmSwift

func createOrUpdateMachineInRealm(machine: Machine){

    let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT

    dispatch_async(dispatch_get_global_queue(priority, 0)) {
        // do some task
        let realm = Realm()

        realm.beginWrite()

        realm.write{
            realm.add(machine, update: true)
        }

        realm.commitWrite()

        dispatch_async(dispatch_get_main_queue()) {
            // update some UI
            actionDelegate?.operationCompleted(true)
        }

    }
}

Solution: I pass in the parameters for machine as well and assign them to the machine within the realm.write()

 func createOrUpdateMachineInRealm(machine: Machine, name: String){

    let priority = DISPATCH_QUEUE_PRIORITY_DEFAULT

    dispatch_async(dispatch_get_global_queue(priority, 0)) {
        // do some task
        let realm = Realm()

        realm.write{
            machine.name = name
            realm.add(machine, update: true)
        }
     }

 }
Margravine answered 10/6, 2015 at 12:27 Comment(0)
L
10

I just had the same problem and exception as you did. Though Nate Mann's answer is not the solution to the problem, it lead me in the right direction.

You can not modify a Realm object you have previously pulled out of the database, because Realm will try to update it and throw an error, when it is (for whatever reason) on a different queue.

So you either have to do all modification inside your realm.write{ } statement or create a new object with the same primary key, so it gets updated correctly. That would also mean that you can't have one function to create or update, but need two separate ones.

Your update function would have to look something like this:

func updateMachineInRealm(machine: Machine){
    var updatedMachine = Machine()
    updatedMachine.name = machine.name
    updatedMachine.value = machine.value + 42
    updatedMachine.primaryKey = machine.primaryKey
    // "transfer" or modify all the values of the old machine object

    let realm = try! Realm()
    do {
        try realm.write() {
        realm.add(updatedMachine, update: true)
    }
}

Remember that you need a unique primary key for this code to work, because that is what Realm will match your new object with in the database.

Also, this of course has drawbacks when working on a bigger project with more than one thread accessing Realm objects etc. But it'll work for small projects (like I was working on and you seem to be working on).

Liftoff answered 31/10, 2015 at 23:55 Comment(0)
H
6

Get rid of realm.beginWrite() and realm.commitWrite(). They are not needed when you use realm.write { }.

Hairstyle answered 10/6, 2015 at 12:33 Comment(3)
Thanks for the reply @NateMann . I am able to add it the first time w/o error. However i got this *** Terminat ing app due to uncaught exception 'RLMException', reason: 'Attempting to modify object outside of a write transaction - call beginWriteTransaction on an RLMRealm instance first.' when i call the method again ( for update).Margravine
Are you adding a machine or updating one. If you are updating one, say machine.name = "Drill", this has to be done in Realm().write { }, like this Realm().write { machine.name = "Drill" }Hairstyle
Is it possible for me to update the Machine object at UI level and pass to Realm() (Storage.swift) for write transaction? I am trying to avoid using Realm at the ViewControllers. Very new to realmSwiftMargravine

© 2022 - 2024 — McMap. All rights reserved.