从不正确的线程访问的领域 - Swift 3
Realm accessed from incorrect thread - Swift 3
在我的 UITableViewController
顶部是以下内容:
let queue = DispatchQueue(label: "background")
删除任务时,执行以下操作:
self.queue.async {
autoreleasepool {
let realm = try! Realm()
realm.beginWrite()
realm.delete(task)
do {
try realm.commitWrite()
} catch let error {
self.presentError()
}
}
}
然后我收到错误
terminating with uncaught exception of type
realm::IncorrectThreadException: Realm accessed from incorrect thread.
我该如何解决这个问题?
似乎写入发生在与最初访问对象不同的线程上。您应该能够通过传递 task
的 id 并在写入之前使用它从数据库中获取它来修复它(在异步块内)。
所以在顶部:
var taskId = 0 // Set this accordingly
然后是
self.queue.async {
autoreleasepool {
let realm = try! Realm()
let tempTask = // get task from Realm based on taskId
realm.beginWrite()
realm.delete(tempTask)
do {
try realm.commitWrite()
} catch let error {
self.presentError()
}
}
}
我们需要了解以下事实无法从不同的线程访问领域对象。这是什么意思以及如何解决这个问题。
首先,realm对象不能被不同的线程访问意味着,一个线程中定义的一个Realm实例不能被不同的线程访问。我们实际上应该做的是我们需要为每个线程拥有不同的领域实例。
例如。让我们看看下面的例子单击按钮后,我们在后台线程中异步向数据库中插入 50 条记录,并在主线程中添加通知块以更新计数标签中的人数。每个线程(主线程和后台线程)都有自己的领域对象实例来访问领域数据库。因为 Realm 数据库通过使 Realm 线程受限的实例来实现线程安全。
class Person: Object {
dynamic var name = ""
convenience init(_ name: String) {
self.init()
self.name = name
}
}
override func viewDidAppear(_ animated: Bool) {
let realmMain = try! Realm ()
self.people = realmMain.objects(Person.self)
self.notification = self.people?.addNotificationBlock{ [weak self] changes in
print("UI update needed")
guard let countLabel = self?.countLabel else {
return
}
countLabel.text = "Total People: \(String(describing: self?.people?.count))"
}
}
@IBAction func addHandler(_ sender: Any) {
print(#function)
let backgroundQueue = DispatchQueue(label: "com.app.queue",
qos: .background,
target: nil)
backgroundQueue.async {
print("Dispatched to background queue")
let realm = try! Realm()
try! realm.write {
for i in 1..<50 {
let name = String(format: "rajan-%d", i)
//print(#function, name)
realm.add(Person(name))
}
}
}
}
您还可以使用 ThreadSafe 引用,这是一种在线程之间传递领域对象的特定方法:
let realm = try! Realm()
let person = Person(name: "Jane") // no primary key required
try! realm.write {
realm.add(person)
}
let personRef = ThreadSafeReference(to: person)
DispatchQueue(label: "com.example.myApp.bg").async {
let realm = try! Realm()
guard let person = realm.resolve(personRef) else {
return // person was deleted
}
try! realm.write {
person.name = "Jane Doe"
}
Realm 文档提供的步骤:
- 使用线程限制对象初始化 ThreadSafeReference。
- 将该 ThreadSafeReference 传递给目标线程或队列。
- 通过调用在目标 Realm 上解析此引用
Realm.resolve(_:)。
- 像往常一样使用返回的对象。
你还可以获得
Realm accessed from incorrect thread
如果您尝试按获取的项目写入
在我的 UITableViewController
顶部是以下内容:
let queue = DispatchQueue(label: "background")
删除任务时,执行以下操作:
self.queue.async {
autoreleasepool {
let realm = try! Realm()
realm.beginWrite()
realm.delete(task)
do {
try realm.commitWrite()
} catch let error {
self.presentError()
}
}
}
然后我收到错误
terminating with uncaught exception of type realm::IncorrectThreadException: Realm accessed from incorrect thread.
我该如何解决这个问题?
似乎写入发生在与最初访问对象不同的线程上。您应该能够通过传递 task
的 id 并在写入之前使用它从数据库中获取它来修复它(在异步块内)。
所以在顶部:
var taskId = 0 // Set this accordingly
然后是
self.queue.async {
autoreleasepool {
let realm = try! Realm()
let tempTask = // get task from Realm based on taskId
realm.beginWrite()
realm.delete(tempTask)
do {
try realm.commitWrite()
} catch let error {
self.presentError()
}
}
}
我们需要了解以下事实无法从不同的线程访问领域对象。这是什么意思以及如何解决这个问题。
首先,realm对象不能被不同的线程访问意味着,一个线程中定义的一个Realm实例不能被不同的线程访问。我们实际上应该做的是我们需要为每个线程拥有不同的领域实例。
例如。让我们看看下面的例子单击按钮后,我们在后台线程中异步向数据库中插入 50 条记录,并在主线程中添加通知块以更新计数标签中的人数。每个线程(主线程和后台线程)都有自己的领域对象实例来访问领域数据库。因为 Realm 数据库通过使 Realm 线程受限的实例来实现线程安全。
class Person: Object {
dynamic var name = ""
convenience init(_ name: String) {
self.init()
self.name = name
}
}
override func viewDidAppear(_ animated: Bool) {
let realmMain = try! Realm ()
self.people = realmMain.objects(Person.self)
self.notification = self.people?.addNotificationBlock{ [weak self] changes in
print("UI update needed")
guard let countLabel = self?.countLabel else {
return
}
countLabel.text = "Total People: \(String(describing: self?.people?.count))"
}
}
@IBAction func addHandler(_ sender: Any) {
print(#function)
let backgroundQueue = DispatchQueue(label: "com.app.queue",
qos: .background,
target: nil)
backgroundQueue.async {
print("Dispatched to background queue")
let realm = try! Realm()
try! realm.write {
for i in 1..<50 {
let name = String(format: "rajan-%d", i)
//print(#function, name)
realm.add(Person(name))
}
}
}
}
您还可以使用 ThreadSafe 引用,这是一种在线程之间传递领域对象的特定方法:
let realm = try! Realm()
let person = Person(name: "Jane") // no primary key required
try! realm.write {
realm.add(person)
}
let personRef = ThreadSafeReference(to: person)
DispatchQueue(label: "com.example.myApp.bg").async {
let realm = try! Realm()
guard let person = realm.resolve(personRef) else {
return // person was deleted
}
try! realm.write {
person.name = "Jane Doe"
}
Realm 文档提供的步骤:
- 使用线程限制对象初始化 ThreadSafeReference。
- 将该 ThreadSafeReference 传递给目标线程或队列。
- 通过调用在目标 Realm 上解析此引用 Realm.resolve(_:)。
- 像往常一样使用返回的对象。
你还可以获得
Realm accessed from incorrect thread
如果您尝试按获取的项目写入