RLMException lors d'une tentative d'exécution d'une transaction Realm avec Grand Central Dispatch

J'ai ces deux déclarés comme globals dans mon AppDelegate

var realmdb: RLMRealm! var realmQueue = dispatch_queue_create("com.pesto.realmdb", DISPATCH_QUEUE_SERIAL) 

Dans mon application(_, didFinishLaunchingWithOptions: _) j'ai défini une reference de defaultRealm à mon realmdb global comme ceci:

  dispatch_async(realmQueue) { realmdb = RLMRealm.defaultRealm() } 

Dans une autre class de mon code, j'ai cette méthode:

 private func handleChatMessage(message: PSTChatMsg) { // check if there is a channel environment for this message PSTChatHelpers.getChannelEnvironmentForChannelName(message.channel) { channelEnvironments in if channelEnvironments.count == 0 { log.verbose("Channel environment for \(message.channel) does not exists. Creating...") let newChannelEnvironment = PSTChatHelpers.createChannelEnvironmentFromMessage(message) PSTChatHelpers.persistChannelEnvironmentChanges(newChannelEnvironment) } else { log.verbose("Pushing message to channel environment") } } } 

et les methods d'appel sont implémentées comme suit:

  class func getChannelEnvironmentForChannelName(channelName: Ssortingng, withCompletionHandler handler: (results: RLMResults) -> ()) { dispatch_async(realmQueue) { let predicate = NSPredicate(format: "channelName = %@", channelName) var channelEnv = PSTChannelEnvironment.objectsInRealm(realmdb, withPredicate: predicate) handler(results: channelEnv) } } /** Creates a new PSTChannelEnvironment object wth values derived from passed PSTChatMsg :param: message a PSTChatMsg to derive channel environment values from :returns: The newly created PSTChannelEnvironment object */ class func createChannelEnvironmentFromMessage(message: PSTChatMsg) -> PSTChannelEnvironment { let channelEnvironment = PSTChannelEnvironment() channelEnvironment.channelName = message.channel channelEnvironment.associatedPlaceId = message.associatedPlaceId channelEnvironment.chattingWithUuid = "" channelEnvironment.chattingWithUsername = "" channelEnvironment.hasSessionEnded = false channelEnvironment.unreadMessages = 0 return channelEnvironment } /** Commits the passed PSTChannelEnvironment in Realm database :param: The PSTChannelEnvironment to commit to Realm */ class func persistChannelEnvironmentChanges(channelEnvironment: PSTChannelEnvironment) { dispatch_async(realmQueue) { realmdb.beginWriteTransaction() realmdb.addObject(channelEnvironment) realmdb.commitWriteTransaction() } } 

Je reçois RLMException, reason: 'Realm accessed from incorrect thread' de la méthode getChannelEnvironmentForChannelName() .

Je suis un peu frustré de la façon dont je peux utiliser GCD pour gérer toutes les opérations de mon royaume, donc toute aide serait grandement appréciée!

Comme il n'y a généralement pas d'association fixe entre les threads et les files d'attente (sans la file principale, qui s'exécute uniquement sur le thread principal et vice-versa), vous ne pouvez pas récupérer une instance RLMRealm dans votre queue. GCD ne donne aucune garantie, que la même queue sera exécutée par le même thread à nouveau.

Je vous recommand de faire reference à votre royaume à la place par une méthode d'usine non caching:

 var realmdb : RLMRealm { return RLMRealm.defaultRealm() } 

Pas de soucis, la méthode d'usine définie sur RLMRealm implémente déjà une stratégie de caching, donc cette opération n'est pas trop chère et vous pouvez toujours mettre en cache l'instance dans une variable locale pour chaque usage.

Si vous voulez le faire circuler pour découpler les classs les unes des autres, vous pouvez toujours l'écrire en tant que type de fonction:

 var realmdb : () -> RLMRealm { return { RLMRealm.defaultRealm() } } 

Vous devriez replace ceci

 dispatch_async(realmQueue) { realmdb.beginWriteTransaction() realmdb.addObject(channelEnvironment) realmdb.commitWriteTransaction() } 

Avec

 dispatch_async(realmQueue) { autoreleasepool { let realmdb = try! Realm() realmdb.beginWriteTransaction() realmdb.addObject(channelEnvironment) realmdb.commitWriteTransaction() } } 

De cette façon, vous vous assurez que l'instance de domaine est fermée et que vous créez une instance de domaine appartenant à ce thread. Une instance de domaine n'est accessible que sur le thread où elle a été créée.