You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift中Realm线程访问异常问题求助(Alamofire下载后更新)

Fixing 'Realm accessed from incorrect thread.' Exception After Alamofire Download

Let's break down why you're hitting this RLMException and how to fix it:

Root Cause

The core issue here is cross-thread access to a Realm object. Even though you wrapped your Realm operations in DispatchQueue.main.async, you're making a critical mistake in the write block: you're modifying two separate ReciterItem instances:

  1. The item you fetch from the main-thread Realm instance (this is valid, as it belongs to the current thread)
  2. self.reciter.item[index] — this object was almost certainly created/fetched on a different thread (like a background thread during initial data loading), so it's tied to that thread's Realm instance. Modifying it directly on the main thread violates Realm's thread-confinement rules.

Solution Steps

1. Remove Cross-Thread Object Modifications

You don't need to modify self.reciter.item[index] at all. Realm objects are live-updating — once you modify the item fetched from the main-thread Realm, any subsequent access to that object (even from your data source) will reflect the changes automatically.

2. Use Parameterized Realm Queries

Avoid string interpolation for filter conditions — it's unsafe and can lead to syntax errors. Use Realm's parameterized queries instead:

let item = realm.objects(ReciterItem.self).filter("id == %@", self.reciter.item[index].id).first!

3. Ensure All Realm Operations Stay Thread-Safe

Never hold a Realm object instance created on one thread and use it on another. Always fetch objects from a Realm instance initialized on the current thread.

Revised Code Snippets

Here's how to update your progress closure:

DispatchQueue.main.async {
    do {
        let realm = try Realm()
        guard let item = realm.objects(ReciterItem.self).filter("id == %@", self.reciter.item[index].id).first else {
            print("ReciterItem not found for id: \(self.reciter.item[index].id)")
            return
        }
        try realm.write {
            item.progress = Float(progress.fractionCompleted)
            // Remove the lines modifying self.reciter.item[index] here
        }
    } catch {
        print("Unexpected error: \(error).")
    }
    self.tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .none)
}

And the response completion handler:

DispatchQueue.main.async {
    do {
        let realm = try Realm()
        guard let item = realm.objects(ReciterItem.self).filter("id == %@", self.reciter.item[index].id).first else {
            print("ReciterItem not found for id: \(self.reciter.item[index].id)")
            return
        }
        try realm.write {
            item.progress = 1.0
            item.isDownloaded = true
            // Remove the lines modifying self.reciter.item[index] here
        }
    } catch {
        print("Unexpected error: \(error).")
    }
    self.tableView.reloadRows(at: [IndexPath(row: index, section: 0)], with: .none)
}

Bonus: Better Data Source Handling

If self.reciter.item is your table view data source, consider using Realm's Results collection directly. Results is auto-updating and thread-safe when accessed correctly — you can even set up Realm notifications to automatically refresh your table view whenever data changes, eliminating manual reload calls entirely.

内容的提问来源于stack exchange,提问作者Ahsan Aasim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.27 07:32:06