Ios 从错误线程访问的域-Swift 3
myIos 从错误线程访问的域-Swift 3,ios,swift,multithreading,realm,grand-central-dispatch,Ios,Swift,Multithreading,Realm,Grand Central Dispatch,myUITableViewController的顶部有以下内容: let queue = DispatchQueue(label: "background") 删除任务时,将执行以下操作: self.queue.async { autoreleasepool { let realm = try! Realm() realm.beginWrite() realm.delete(task) do { t
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()
}
}
}
然后我收到了错误
以类型为的未捕获异常终止
realm::IncorrectThreadException:从错误线程访问的领域
如何修复此问题?似乎写入发生在与最初访问对象不同的线程上。您应该能够通过传递
任务
的id来修复它,并在写入之前(在异步块内)使用该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()
}
}
}
我们需要了解不能从不同线程访问领域对象的事实。这意味着什么以及如何解决这个问题 首先,领域对象不能从不同的线程访问意味着,一个线程中定义的领域实例不能从不同的线程访问。我们实际上应该做的是,我们需要为每个线程提供不同的领域实例实例 例如,让我们看看下面的例子,我们在后台线程中异步插入50条记录,点击按钮,然后在主线程中添加通知块,以更新计数标签中的人数。每个线程(主线程和后台线程)都有自己的领域对象实例来访问领域数据库。因为领域数据库通过限制领域线程实例来实现线程安全
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))
}
}
}
}
类人物:对象{
动态变量名称=“”
便利初始化(u名称:String){
self.init()
self.name=名称
}
}
覆盖函数视图显示(u动画:Bool){
让realmMain=try!Realm()
self.people=realmMain.objects(Person.self)
self.notification=self.people?.addNotificationBlock{[weak self]中的更改
打印(“需要UI更新”)
guard let countLabel=self?.countLabel else{
返回
}
countLabel.text=“总人数:\(字符串(描述:self?.People?.count))”
}
}
@iAction func addHandler(\发送方:任意){
打印(#功能)
让backgroundQueue=DispatchQueue(标签:“com.app.queue”,
服务质量:。背景,
目标:零)
backgroundQueue.async{
打印(“发送到后台队列”)
让realm=try!realm()
试试看!写吧{
对于1..中的i,您还可以使用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.resolve(\:)
像平常一样使用返回的对象
你也可以
Realm accessed from incorrect thread
如果您试图通过获取的项写入,那么我无法从主线程(UI线程)读取如果我想写?我应该重新考虑使用线程吗?是的,当对象在线程之间传递时,领域会崩溃。这在我身上发生过很多次:)如果我还必须进行额外的读取,你认为线程化写有什么好处吗?谢谢!这就是我们建议卸载的方式工作到后台线程。您可以将taskId
设置为域对象的主键,然后使用Realm.object(ofType:forPrimaryKey:)在后台线程上检索对它的引用
。根据一般经验,我们建议尽可能将持久的领域写入事务卸载到后台线程。在写入过程中,可以在其他线程上继续从领域读取,但需要注意的是,如果在后台正在进行写入,而您尝试在主线程上启动一个,则可能会导致错误检查UI,直到后台操作完成。