Realm-cocoa: refresh() doesn't work

Created on 23 Nov 2017  路  6Comments  路  Source: realm/realm-cocoa

Goals


I want get realm object from main thread after write in background.

Expected Results


write in background, refresh, get object in main thread too

Actual Results


write in background, refresh, no object in main ( only after runloop is done)

Steps to Reproduce

Code Sample


func getEntity(id: String?) -> E? {

    print("save getEntity with id", self)

    guard id != nil else {
        return nil
    }

    let realm = try! loadRealm()
    realm.refresh()

    return realm.object(ofType: E.self, forPrimaryKey: id)
}

func loadRealm() throws -> Realm {
    let configuration = Realm.Configuration(encryptionKey: getKey() as Data)
    do {
        let realm = try Realm(configuration: configuration)
        return realm
    }
    catch  {
        throw DataModelError.decryptionFailed
    }
}

Version of Realm and Tooling


Realm framework version: ?

Realm Object Server version: ?
Installing Realm 3.0.2 (was 2.10.2)
Installing RealmSwift 3.0.2 (was 2.10.2)

Xcode version: ?
Version 8.3.3

iOS/OSX version: ?
10.3

Dependency manager + version: ?
Cocoapods

T-Help

Most helpful comment

Problem was that I send object before transaction is ended.

Yep, that'll do it. refresh() advances a Realm to the most recent version of data in the Realm file, and if the transaction has not yet been committed then no new version has been created.

Looking at this slightly simplified version of your code:

let realm = try! self.loadRealm()
realm.refresh()

realm.safeWrite {
    realm.add(realmEntity, update:true)
    realm.refresh()
}

realm.refresh()

Every call to realm.refresh() in this code snippet is redundant.

  • Beginning a write transaction inherently requires advancing to the latest version, so calling refresh() prior to that is redundant.

  • Calling refresh() within a write transaction has no effect as the write transaction must always be working with the most recent version of data in the Realm.

  • Calling refresh() immediately after a write transaction is unlikely to do anything as the Realm was already at the most recent version when the write transaction was committed, and it's incredibly unlikely that another thread was able to commit a write transaction in the mean time.

All 6 comments

Your problem mentions a problem involving threads, but the code snippet you've shared doesn't involve threads at all. Please share code that demonstrates the problem you're having.

Sorry, I can't share this code. Thats why I just described my problem.

@mamaral Could you please share sample reproducible code instead of your actual code? Because problems caused by multithreading are hard to predict, so we do not know what is happening by just describing the problem.

@kishikawakatsumi
Im not sure about recreating whole code, but could you say, if there any reason why after realm.add and realm.refresh needed object didn't appear in db (checked also using Realm Browser)?

func save(apiEntity: A) -> Signal<E, KZDMError>  {

    return Signal { obs in

        let realm = try! self.loadRealm()
        realm.refresh()

        realm.safeWrite {

            print("save apiEntity signal", self)

            var realmEntity = E()

            realmEntity = self.mapper.map(entity: realmEntity, apiEntity: apiEntity)
            realm.add(realmEntity, update:true)
            realm.refresh()
            print("refresh")


            obs.next(realmEntity)
            obs.completed()
        }

        realm.refresh()


        return BlockDisposable { }
    }
}
extension Realm {
    public func safeWrite(_ block:  (()  -> Void))  {
        if isInWriteTransaction {
            block()
        } else {
          try!  write(block)
        }
    }
}

object I'm trying to save looks like:

open class SomeObject: Object {
    public dynamic var id = NSUUID().uuidString

    override open static func primaryKey() -> String? {
        return "id"
    }

    // some other fields
}


I just need some suggestions about where problem could hide. Thanks :-)

w/e, I fixed it. Problem was that I send object before transaction is ended:

    realm.safeWrite {
        realm.add(realmEntity, update:true)

        obs.next(realmEntity)
        obs.completed()
    }

into

        realm.beginWrite()
        realm.add(realmEntity, update:true)
        try! realm.commitWrite()

        obs.next(realmEntity)
        obs.completed()

Maybe it could help somebody :)

Problem was that I send object before transaction is ended.

Yep, that'll do it. refresh() advances a Realm to the most recent version of data in the Realm file, and if the transaction has not yet been committed then no new version has been created.

Looking at this slightly simplified version of your code:

let realm = try! self.loadRealm()
realm.refresh()

realm.safeWrite {
    realm.add(realmEntity, update:true)
    realm.refresh()
}

realm.refresh()

Every call to realm.refresh() in this code snippet is redundant.

  • Beginning a write transaction inherently requires advancing to the latest version, so calling refresh() prior to that is redundant.

  • Calling refresh() within a write transaction has no effect as the write transaction must always be working with the most recent version of data in the Realm.

  • Calling refresh() immediately after a write transaction is unlikely to do anything as the Realm was already at the most recent version when the write transaction was committed, and it's incredibly unlikely that another thread was able to commit a write transaction in the mean time.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

dennisgec picture dennisgec  路  3Comments

ishidakei picture ishidakei  路  3Comments

TheHmmka picture TheHmmka  路  3Comments

duribreux picture duribreux  路  3Comments

fadylateef picture fadylateef  路  3Comments