Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RLMRealm instance was deallocated during a write transaction #3302

Closed
jeeftor opened this issue Mar 8, 2016 · 8 comments
Closed

RLMRealm instance was deallocated during a write transaction #3302

jeeftor opened this issue Mar 8, 2016 · 8 comments
Labels

Comments

@jeeftor
Copy link

jeeftor commented Mar 8, 2016

So my realm has has been crashing randomly and i've been having trouble tracking it down. My device wasn't leaving crash logs but when running attached to Xcode i finally got this error in the console:

Mar 8 13:26:49 Black-Taco gaard2[1370] : WARNING: An RLMRealm instance was deallocated during a write transaction and all pending changes have been rolled back. Make sure to retain a reference to the RLMRealm for the duration of the write transaction.
Mar 8 13:26:49 Black-Taco gaard2[1370] : WARNING: An RLMRealm instance was deallocated during a write transaction and all pending changes have been rolled back. Make sure to retain a reference to the RLMRealm for the duration of the write transaction.
Mar 8 13:26:49 Black-Taco gaard2[1370] : WARNING: An RLMRealm instance was deallocated during a write transaction and all pending changes have been rolled back. Make sure to retain a reference to the RLMRealm for the duration of the write transaction.
Mar 8 13:26:49 Black-Taco gaard2[1370] : WARNING: An RLMRealm instance was deallocated during a write transaction and all pending changes have been rolled back. Make sure to retain a reference to the RLMRealm for the duration of the write transaction.
Mar 8 13:26:50 Black-Taco gaard2[1370] : WARNING: An RLMRealm instance was deallocated during a write transaction and all pending changes have been rolled back. Make sure to retain a reference to the RLMRealm for the duration of the write transaction.

So as far as I can tell i'm using the following code block - but i'm confused as to why this can happen:

dispatch_async(realmQueue) {
            autoreleasepool{

                let newConfig = Realm.Configuration(path: config?.path, objectTypes: config?.objectTypes)

                do {

                    let rlm = try Realm(configuration: newConfig)
                    let ml = rlm.objectForPrimaryKey(MessageList.self, key: 0)

                    rlm.beginWrite()
                    for msg in messages {

                        switch (msg) {

                        case _ where msg is dmLocationMessage:
                            let dmsg : dmLocationMessage = msg as! dmLocationMessage
                            let locMsg = LocationMessage(locMsg: dmsg)
                            ml?.locationMessages.append(locMsg)

                        case _ where msg is dmStatusMessage:
                            let dmsg : dmStatusMessage = msg as! dmStatusMessage
                            let statMsg = StatusMessage(statusMsg: dmsg)
                            ml?.statusMessages.append(statMsg)

                        case _ where msg is dmAHRSMessage:
                            let dmsg : dmAHRSMessage = msg as! dmAHRSMessage
                            let ahrsMsg = AHRSMessage(ahrsMsg: dmsg)
                            ml?.ahrsMessages.append(ahrsMsg)

                        case _ where msg is dmTrafficMessage:
                            let dmsg : dmTrafficMessage = msg as! dmTrafficMessage
                            let tfcMsg = TrafficMessage(trafficMsg: dmsg)
                            ml?.trafficMessages.append(tfcMsg)

                        default:
                            Log.dm.warning("Unrecognized Type: \(msg)")
                            break;
                        } // end switch
                    } // end for

                    try rlm.commitWrite()
                    Log.dm.debug("Wrote to \(rlm.path)")

                } catch let error as NSError {
                    Log.dm.error("Data Writing Error \(error)")
                }

                self.delegate?.didRecordDataManagerData(msg, wasWritten: true)
            } // end autopool
        } // end dispatch async

It "looks" like i'm just creating a realm on a background queue INSIDE of an autorelease block - so maybe its not here? Is there an easy way to track this error down?

@mrackwitz
Copy link
Contributor

Yeah, this looks like your RLMRealm instance wouldn't be deallocated in the provided code sample within the write transaction.
For further tracking this down, I'd recommend setting a breakpoint on the line which logs the warning (RLMRealm.mm:587 on master), if you integrate Realm from source compiled yourself in a manual integration or via CocoaPods. If you use prebuilt binaries, then you could set a symbol breakpoint on [RLMRealm dealloc]. When you hit this breakpoint, the entries further down on the stack trace should give you some hint where this happens.

@bdash
Copy link
Contributor

bdash commented Mar 9, 2016

The posted code does not appear to be safe in the face of errors. It will leave the transaction uncommitted in that case. Using Realm.write(_:) rather than beginWrite() / commitWrite() would fix that issue with the code.

@mrackwitz
Copy link
Contributor

Oh, absolutely! How could I have missed that. Mark is right on that. 👍

@geraldeersteling
Copy link

geraldeersteling commented Jul 5, 2017

@bdash I'm sorry to re-open this issue; but I'm failing to see where the transaction would be left uncomitted... 😶

Or is a (possibly) failing commitWrite() inherently the one which also leaves the transaction uncommitted? If so, what would be a solution to that?

Also; say (in the above context) I wanted to save/update multiple objects (~100), is it more efficient to do this in beginWrite()/commitWrite() blocks or is it "ok" to do this in a for loop with Realm.write(_:) blocks?

@bdash
Copy link
Contributor

bdash commented Jul 5, 2017

Realm.write(_:)'s implementation looks like so:

public func write(_ block: (() throws -> Void)) throws {
    beginWrite()
     do {
          try block()
    } catch let error {
          if isInWriteTransaction { cancelWrite() }
          throw error
    }
    if isInWriteTransaction { try commitWrite() }
}

The relevant portion is the call to cancelWrite() in the catch block if the Realm was still in a write transaction.

If you're going to update multiple objects, it's preferable to do so within a single transaction. Whether you create the transaction using Realm.write(_:) or Realm.beginWrite() doesn't affect performance, only the number of transactions you create and commit.

@geraldeersteling
Copy link

geraldeersteling commented Jul 5, 2017

Ah I see, thanks for elaborating on this! I think I understand it a little more now (I just started with Realm a few hours ago).

So if I'm following you right:

// Assuming a realm was created in the current thread and the write won't fail
try! realm.write {
    // #1 One can perform updates/insertions here? E.g.
    realm.add(someThing, update: true)
    realm.add(someOtherThing, update: true)

    // #2 What about 'for'-loops here?
    for thing in allTheThings {
        realm.add(thing, update: true)
    }
}

In the above context; would that write transaction follow through correctly?

Sorry if I'm asking too much

@bdash
Copy link
Contributor

bdash commented Jul 5, 2017

I'm not sure quite what you're asking there. The code you've provided looks sensible though.

@geraldeersteling
Copy link

Ah, never mind. I think I got it now, I misunderstood the write block.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 15, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Projects
None yet
Development

No branches or pull requests

5 participants