如何打造跨线程无崩溃的Realm包装器并优化性能
解决方案
1. 线程专属Realm实例缓存
Realm实例不支持跨线程复用,这是你之前缓存全局实例崩溃的核心原因。正确的做法是为每个线程单独缓存Realm实例,利用Thread.current.threadDictionary存储当前线程的专属实例:
import Foundation import RealmSwift import Realm class RealmStorage: LocalStoring { private static let configuration: Realm.Configuration = { let schemaString = Bundle.main.object(forInfoDictionaryKey: "Realm Schema") as? String ?? "" let schema = UInt64(schemaString) ?? 1 return Realm.Configuration(schemaVersion: schema) }() private let category: String init(category: String) { self.category = category } // 获取当前线程的专属Realm实例 private func realmForCurrentThread() throws -> Realm { let threadKey = "RealmStorage_\(category)" let threadDictionary = Thread.current.threadDictionary if let existingRealm = threadDictionary[threadKey] as? Realm { return existingRealm } let newRealm = try Realm(configuration: RealmStorage.configuration) threadDictionary[threadKey] = newRealm return newRealm } // 修改原有方法,使用线程专属实例 func store<T: Object>(_ object: T) { do { let realm = try realmForCurrentThread() try realm.write { realm.add(object, update: .all) } } catch { print("Realm error: \(error.localizedDescription)") } } func update<T: Object>(_ object: T, value: Any?, for key: String) { do { let realm = try realmForCurrentThread() try realm.write { object.setValue(value, forKey: key) } } catch { print("Realm error: \(error.localizedDescription)") } } func retrieve<T: Object>(_ objectType: T.Type) -> [T] { guard let realm = try? realmForCurrentThread() else { return [] } let objects = realm.objects(objectType.self) return Array(objects) } func remove<T: Object>(_ objectType: T.Type, where condition: @escaping (T) -> Bool) { do { let realm = try realmForCurrentThread() try realm.write { let objects = realm.objects(objectType.self).filter(condition) realm.delete(objects) } } catch { print("Realm error: \(error.localizedDescription)") } } func removeAll<T: Object>(_ objectType: T.Type) { do { let realm = try realmForCurrentThread() try realm.write { let objects = realm.objects(objectType.self) realm.delete(objects) } } catch { print("Realm error: \(error.localizedDescription)") } } }
这个方案既避免了跨线程崩溃,又不用每次操作都重新初始化Realm,能有效提升性能。
2. 预加载Realm减少初始化开销
在App启动时提前初始化主线程的Realm实例,让Realm提前完成文件加载和schema校验,后续主线程操作会更流畅:
// 在AppDelegate或SceneDelegate的启动方法中添加 func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { do { // 预加载主线程Realm实例 _ = try Realm(configuration: RealmStorage.configuration) } catch { print("Realm preload error: \(error.localizedDescription)") } return true }
3. 批量合并操作
如果存在多个连续的数据操作,合并到同一个Realm write块中,减少实例初始化次数:
// 新增批量存储方法 func storeBatch<T: Object>(_ objects: [T]) { do { let realm = try realmForCurrentThread() try realm.write { objects.forEach { realm.add($0, update: .all) } } } catch { print("Realm batch error: \(error.localizedDescription)") } }
4. 异步操作优化体验
对于耗时的读写操作,使用Realm的异步API,避免阻塞主线程,同时Realm内部会优化实例复用:
// 新增异步存储方法 func storeAsync<T: Object>(_ object: T, completion: ((Error?) -> Void)?) { Realm.asyncOpen(configuration: RealmStorage.configuration) { result in switch result { case .success(let realm): do { try realm.write { realm.add(object, update: .all) } completion?(nil) } catch { completion?(error) } case .failure(let error): completion?(error) } } }
不推荐双数据源方案:内存数组+Realm的组合很容易出现数据不一致(比如异步操作未同步、线程竞态),会增加调试和维护成本,上述方案更稳定可靠。
内容的提问来源于stack exchange,提问作者Bawenang Rukmoko Pardian Putra
相关产品推荐
相关产品推荐

