【发布时间】:2017-07-28 14:01:53
【问题描述】:
所以我有一个单例类来管理登录到我的应用程序的当前用户。
看起来像这样
class SessionManager {
static let shared = SessionManager()
var loggedInUser: User?
}
问题是,如果我想从后台线程获取该用户对象,我不能,因为我得到以下异常:
'RLMException', reason: 'Realm accessed from incorrect thread.'
经过一番谷歌搜索后,我找到了线程安全参考。所以我把我的班级改成这样:
class SessionManager {
static let shared = SessionManager()
private var threadSafeUser: ThreadSafeReference<User>?
var loggedInUser: User? {
get {
if nil === self.threadSafeUser {
return nil
} else {
let realm = try! Realm()
return realm.resolve(self.threadSafeUser!)!
}
}
set {
if nil === newValue {
self.threadSafeUser = nil
} else {
self.threadSafeUser = ThreadSafeReference(to: newValue!)
}
}
}
}
我的想法是我在内部持有一个线程安全的引用,然后每当我获取用户对象时,我都会解析该对象。但是这不起作用,因为您只能解析一次 ThreadSafeReference:
'RLMException', reason: 'Can only resolve a thread safe reference once.'
我也尝试过在 getter 中解决它一次,但是如果您将已解决的对象从不同的线程引用到解决它的位置,则会遇到第一个问题。
目前我能想到两种选择:
我为每个线程保留一个引用,并传回正确的线程用户对象(不是 100% 确定我会怎么做,目前只是一个理论)
我可以将我的 set/get 调度到主线程以同步获取对象。所以我总是从主线程中获取它。我可能无法将更改写入对象,但也许我可以阅读?老实说,不确定这是否真的有效。
考虑到问题的普遍性,我 100% 确定这是一个以前解决过的问题。
那么各位领域用户,我该如何解决呢?
编辑:感谢下面的大卫解决了问题。对于其他 S.O 用户,这就是我最后所做的。
class SessionManager {
static let shared = SessionManager()
private var loggedInUserId: Int?
var loggedInUser: User? {
get {
if nil == loggedInUserId {
return nil
}
let realm = try! Realm()
return realm.object(ofType: User.self, forPrimaryKey: loggedInUserId)
}
set {
if nil == newValue {
loggedInUserId = nil
} else {
loggedInUserId = newValue!.id
}
}
}
}
它可能需要一些清理(nil 检查肯定可以写得更好),但这是我采用的基本方法。
这让我可以像对待普通对象一样对待loggedInUser 属性,并且每当我阅读它时,它都会从领域(线程安全)中获取一个新引用,如果我想设置一个新用户(即登录后) ),我可以 loggedInUser = newUser 和 setter 处理如何持久化它。
【问题讨论】:
-
在问题的末尾写下解决方案是一个坏主意恕我直言:当我遇到关于 SO 的问题时,很多时候我会浏览所有代码块以查看 没有工作。在您的情况下 - 最后一个代码块 确实 工作,所以它可能会产生误导。
标签: multithreading swift3 thread-safety realm