ios - 尝试使用 Grand Central Dispatch 执行 Realm 事务时出现 RLMException

标签 ios swift realm

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

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

在我的 application(_, didFinishLaunchingWithOptions: _) 中,我将 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()

    }
}

我从 getChannelEnvironmentForChannelName() 方法中得到 RLMException,原因:“从不正确的线程访问 Realm ”

我对如何使用 GCD 来处理我所有的 Realm 操作感到有点沮丧,因此非常感谢任何帮助!

最佳答案

由于通常线程和队列之间没有固定的关联(没有主队列,主队列只在主线程上运行,反之亦然),你不能只检索一个 RLMRealm 实例通过调度到您的队列并缓存它。 GCD 不保证同一个队列将再次由同一个线程执行。

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

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

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

如果你想传递它来解耦类之间的关系,你仍然可以将它写成一个函数类型:

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

关于ios - 尝试使用 Grand Central Dispatch 执行 Realm 事务时出现 RLMException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28646323/

相关文章:

ios - ActionSheet 源 View BarButtonItem

ios - 如何使用 Segue 将 PHAsset 数组传递到另一个 ViewController

从不正确的线程访问 Java android Realm

ios - Swift Realm - 查询空集但数据位于 RealmBrowser 中

javascript - IOS 应用程序 webview SVG ClipPath 问题

ios - 像 PhotosApp 这样的 Collectionview SubImages

ios - iOS 应用程序在其 bundle 中是否具有写入权限?

ios - 尽管嵌入在 NavigationController 中,但 UINavigationBar 未显示

swift - 禁止直接赋值的可变属性 - Swift

swift - 如何减少存储在 Realm 中的嵌套对象的可变性?