2015-09-11 14 views
7

Ho una configurazione simile al seguente:dati scritti uno sfondo Realm non è disponibile immediatamente per Realm principale

// 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()) 
    } 
} 

Inizialmente ho avuto un writeRealm ma poiché GCD non dà alcuna garanzia su quale filo di un blocco in una coda viene eseguito, sono stato costretto a creare un nuovo Realm ogni volta nella funzione di scrittura.

Ho poi hanno un func pubblico:

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

Questo consente al chiamante di passare in un blocco in cui può fare qualsiasi importazione, e poi prendere qualsiasi importazione sul thread principale quando la promessa si risolve. Il problema è che a volte i dati importati sono disponibili per lo Realm sul thread principale e, a volte, non lo sono. C'è un approccio migliore qui?

MODIFICA: solo per chiarire, se cambio la funzione write per accedere al dominio predefinito in entrambi i casi, passano tutti i miei test.

SOLUZIONE:

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) 
    } 
} 

SOLUZIONE 2: (After semplificando ulteriormente)

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) 
    } 
} 

risposta

8

tl; dr; chiamare Realm.refresh() per far avanzare una transazione allo stato più recente.

Le transazioni del realm sono isolate per garantire l'autosostenibilità. Ciò consente di eseguire transazioni su qualsiasi thread, in qualsiasi momento, senza che sia necessario bloccare o utilizzare esplicitamente altri tipi di coordinamento delle risorse.

Entrambe le transazioni di lettura e scrittura in Realm si basano sul commit di scrittura riuscito più recente quando è stato inizializzato per la prima volta e rimangono su tale versione fino all'aggiornamento. I reami vengono aggiornati automaticamente all'inizio di ogni iterazione di runloop, a meno che la proprietà autorefresh di Realm sia impostata su false. Se un thread non ha runloop (che è generalmente il caso in un thread in background), quindi Realm.refresh() deve essere chiamato manualmente per far avanzare la transazione allo stato più recente.

I registri vengono inoltre aggiornati quando vengono impegnate transazioni di scrittura (Realm.commitWrite()).

+0

Incredibile ha funzionato, grazie! Funzioni aggiornate pubblicate sopra, puoi confermare che ho bisogno di richiamare l'aggiornamento in entrambe le funzioni 'get'? – Andrew

+0

Anche l'aggiornamento della chiamata in 'getDefaultRealm' funziona anche per i miei test correnti, quindi non sono sicuro di quanto sia necessario richiamare l'aggiornamento sullo sfondo. – Andrew