尝试通过Grand Central Dispatch执行Realm事务时出现RLMException [英] RLMException when trying to perform Realm transaction with Grand Central Dispatch

查看:94
本文介绍了尝试通过Grand Central Dispatch执行Realm事务时出现RLMException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在AppDelegate中将这两个声明为全局变量

I have these two declared as globals in my AppDelegate

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

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

In my application(_, didFinishLaunchingWithOptions: _) I set a reference of defaultRealm to my global realmdb like so:

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

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

In another class in my code I have this method:

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

        }

    }
}

和调用方法的实现方式如下:

and the calling methods are implemented like so:

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

    }
}

我正在从方法getChannelEnvironmentForChannelName()中获取RLMException, reason: 'Realm accessed from incorrect thread'.

我对如何使用GCD处理我的所有Realm操作感到有些沮丧,因此我们将不胜感激!

I am a little frustrated on how I can use GCD to handle all my Realm operations so any help would be highly appreciated!

推荐答案

由于线程和队列之间通常没有固定的关联(没有主队列,该队列仅在主线程上运行,反之亦然),您可以不仅可以通过分派到您的队列并对其进行缓存来检索RLMRealm实例. GCD不保证相同的队列将由相同的线程再次执行.

As there is in general no fixed association between threads and queues (without the main queue, which only runs on the main thread and vice-versa), you can't just retrieve a RLMRealm instance by dispatching to your queue and cache it. GCD gives no guarantee, that the same queue will be executed by the same thread again.

我建议通过非缓存工厂方法来引用您的领域:

I'd recommend to refer to your Realm instead by a non-cached factory method:

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

不用担心,在RLMRealm上定义的工厂方法本身已经实现了缓存策略,因此此操作并不太昂贵,您仍然可以按每次使用情况将实例缓存在本地var中.

No worries, the factory method defined on RLMRealm itself implements already a caching strategy, so this operation is not too expensive and you can still cache the instance in a local var per each usage.

如果要传递它以使类彼此分离,则仍然可以将其编写为函数类型:

If you want to pass it around to decouple classes from each other, you can still write it as a function type:

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

这篇关于尝试通过Grand Central Dispatch执行Realm事务时出现RLMException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆