2015-09-11 1 views
7

У меня есть установки, как следующее:Данные, записанные на фоне Realm не доступен сразу к основному Realm

// 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 но поскольку НОД не дает никаких гарантий относительно того, какой поток блок в очереди запускается, мне приходилось создавать новый Realm каждый раз в функции записи.

Я тогда общественное FUNC:

/** 
    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 
} 

Это позволяет вызывающему абоненту перейти в блок, где он может сделать любой импорт, а затем выборки любой импорт в основном потоке, когда обещание решает. Проблема в том, что иногда импортируемые данные доступны для Realm на основном потоке, а иногда и нет. Есть ли лучший подход здесь?

EDIT: Просто уточнить, если я изменяю функцию 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) 
    } 
} 

ответ

8

TL; др; звоните Realm.refresh(), чтобы совершить транзакцию до последнего состояния.

Операции Realm изолированы для обеспечения самосогласования. Это позволяет выполнять транзакции в любом потоке в любое время, не требуя при этом явного блокирования или использования других типов координации ресурсов.

Обе транзакции чтения и записи в Realm основаны на последнем успешном завершении записи при первом инициализации и остаются в этой версии до обновления. Realms автоматически обновляется в начале каждой итерации runloop, если для свойства Realm's autorefresh установлено значение false. Если нить не имеет runloop (что обычно имеет место в фоновом потоке), то Realm.refresh() необходимо вызвать вручную, чтобы перевести транзакцию в самое последнее состояние.

Царства также обновляются после совершения транзакций записи (Realm.commitWrite()).

+0

Удивительно, это сработало, спасибо! Опубликованные обновленные функции выше, можете ли вы подтвердить, что мне нужно вызвать обновление в обеих функциях 'get'? – Andrew

+0

Только обновление вызова в 'getDefaultRealm' также работает для моих текущих тестов, поэтому я не уверен, как нужно называть refresh на фоне Realm. – Andrew

Смежные вопросы