尝试使用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它的线程上访问。