【问题标题】:Data written to a background Realm is not available immediately to main Realm写入后台 Realm 的数据不能立即用于主 Realm
【发布时间】:2015-09-11 14:59:08
【问题描述】:

我有如下设置:

// Queues
private static let mainQueue = dispatch_get_main_queue()
private static let writeQueue = dispatch_queue_create("com.tablelist.Tablelist.queue.realm.write", DISPATCH_QUEUE_SERIAL)

// Realms
private static let defaultRealm: Realm = try! Realm()

private static func getDefaultRealm(block: (Realm) -> ()) {
    Dispatch.async(mainQueue) {
        block(defaultRealm)
    }
}

private static func getWriteRealm(block: (Realm) -> ()) {
    Dispatch.async(writeQueue) {
        block(try! Realm())
    }
}

最初我有一个writeRealm,但由于GCD 不能保证队列中的块运行在哪个线程上,所以我不得不每次在写函数中创建一个新的Realm

然后我有一个公共函数:

/**
    Asynchronously write data to the realm
*/
public static func write(block: (Realm) -> ()) -> Promise<Realm> {
    let promise = Promise<Realm>()

    getWriteRealm { writeRealm in
        do {
            try writeRealm.write {
                block(writeRealm)
            }
            getDefaultRealm { realm in
                promise.resolve(realm)
            }
        }
        catch {
            Dispatch.main {
                promise.resolve(error)
            }
        }
    }

    return promise
}

这允许调用者传入一个可以进行任何导入的块,然后在 promise 解决时在主线程上获取任何导入。问题是,有时导入的数据可用于主线程上的Realm,有时则不能。这里有更好的方法吗?

编辑:澄清一下,如果我在这两种情况下更改 write 函数以获取默认领域,我的所有测试都会通过。

解决方案:

private static func getDefaultRealm(block: (Realm) -> ()) {
    Dispatch.async(mainQueue) {
        defaultRealm.refresh() // refresh the realm to bring to most recent state
        block(defaultRealm)
    }
}

private static func getWriteRealm(block: (Realm) -> ()) {
    Dispatch.async(writeQueue) {
        let realm = try! Realm()
        realm.refresh() // refresh the realm to bring to most recent state
        block(realm)
    }
}

解决方案2:(进一步简化后)

private static func getDefaultRealm(block: (Realm) -> ()) {
    let queue = dispatch_get_main_queue()
    getRealm(queue, block: block)
}

private static func getWriteRealm(block: (Realm) -> ()) {
    let queue = dispatch_queue_create("com.tablelist.Tablelist.queue.realm.write", nil)
    getRealm(queue, block: block)
}

private static func getRealm(queue: dispatch_queue_t, block: (Realm) -> ()) {
    Dispatch.async(queue) {
        let realm = try! Realm()
        realm.refresh()
        block(realm)
    }
}

【问题讨论】:

    标签: swift realm


    【解决方案1】:

    tl;博士;调用Realm.refresh() 将事务推进到最新状态。

    Realm 的事务被隔离以提供自我一致性。这允许随时在任何线程上执行事务,而无需您显式锁定或使用其他类型的资源协调。

    Realm 中的读取和写入事务都基于第一次初始化时最近成功的写入提交,并保持在该版本上直到刷新。除非 Realm 的 autorefresh 属性设置为 false,否则 Realms 会在每次 runloop 迭代开始时自动刷新。如果线程没有运行循环(后台线程通常是这种情况),则必须手动调用 Realm.refresh() 以将事务推进到最近的状态。

    当写入事务提交时,领域也会刷新 (Realm.commitWrite())。

    【讨论】:

    • 效果惊人,谢谢!上面发布了更新的函数,你能确认我需要在 get 函数中调用刷新吗?
    • 仅在 getDefaultRealm 中调用 refresh 也适用于我当前的测试,所以我不确定在后台 Realm 上调用 refresh 的必要性。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-07-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多