Swift中Realm线程访问异常问题求助(Alamofire下载后更新)
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:
- The
itemyou fetch from the main-thread Realm instance (this is valid, as it belongs to the current thread) 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

