尝试使用Grand Central Dispatch执行Realm事务时的RLMException

我有这两个在我的AppDelegate声明为全局

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

在我的application(_, didFinishLaunchingWithOptions: _)中,我为全局realmdb设置了defaultRealm的引用, realmdb所示:

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

在我的代码中的另一个类中,我有这个方法:

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

而调用方法是这样实现的:

  class func getChannelEnvironmentForChannelName(channelName: String, 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() } } 

我得到RLMException, reason: 'Realm accessed from incorrect thread'方法getChannelEnvironmentForChannelName()RLMException, reason: 'Realm accessed from incorrect thread'

我有点沮丧,我怎么可以使用GCD来处理我所有的领域操作,所以任何帮助将不胜感激!

由于线程和队列之间没有固定的关联(没有主队列,只在主线程上运行,反之亦然),所以不能通过调度到队列并caching来获取RLMRealm实例。 GCD不保证,相同的队列将再次被同一个线程执行。

我build议使用非caching工厂方法来引用您的Realm:

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

不用担心,在RLMRealm本身定义的工厂方法实现了一个caching策略,所以这个操作不是太昂贵,你仍然可以caching实例在每个用法的本地RLMRealm

如果你想传递它们来将类互相分离,你仍然可以把它写成一个函数types:

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

你应该replace这个

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

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

这样,您可以确保Realm实例已closures,并且创build属于该给定线程的Realm实例。 Realm实例只能在创build它的线程上访问。