我在我的 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/