尝试通过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() }
}