问题
I have update DataBase in background. My data can contain ~2000 items and it take time to update.
func updateData(items: [JSON], _ complete:@escaping() -> Void) {
DispatchQueue.global(qos: .userInitiated).async {
let currentModels = EgrnModel.getAllModels()
var newModels: [EgrnModel] = []
var toDelete: [EgrnModel] = []
for model in currentModels {
let contain = items.contains(where: {$0["id"].intValue == model.id})
if !contain {
toDelete.append(model)
}
}
let realm = try! Realm()
try! realm.write {
for item in items {
if let model = currentModels.first(where: {$0.id == item["id"].intValue}) {
model.update(item)
}
else {
newModels.append(EgrnModel(item))
}
}
realm.delete(toDelete)
realm.add(newModels)
}
DispatchQueue.main.async {
complete()
}
}
}
and I have a function in which I need update data momentarily. When I tap checkmark I have a freeze. (I think it because at this time other data is updating in background)
func checkMark(index: Int) {
let model = models[index]
let realm = try! Realm()
try! realm.write {
model.needToUpdateOnServer = true
model.lastEditUpdate = Date()
model.read = true
}
}
I try next code to fix a freeze. But in this code I have a crash Terminating app due to uncaught exception 'RLMException', reason: 'Realm accessed from incorrect thread.
func checkMark(index: Int) {
let model = models[index]
DispatchQueue.global(qos: .userInitiated).async {
let realm = try! Realm()
try! realm.write {
model.needToUpdateOnServer = true
model.lastEditUpdate = Date()
model.read = true
}
}
}
回答1:
What you need to is "move" realm objects from one thread to another because realm objects are not thread-safe but Thread Confined. To achieve this you have to use ThreadSafeReference
API.
To solve this problem do the following:
- Create an extension on the realm class
extension Realm {
func writeAsync<T : ThreadConfined>(obj: T, errorHandler: @escaping ((_ error : Swift.Error) -> Void) = { _ in return }, block: @escaping ((Realm, T?) -> Void)) {
let wrappedObj = ThreadSafeReference(to: obj)
let config = self.configuration
DispatchQueue(label: "background").async {
autoreleasepool {
do {
let realm = try Realm(configuration: config)
let obj = realm.resolve(wrappedObj)
try realm.write {
block(realm, obj)
}
}
catch {
errorHandler(error)
}
}
}
}
}
- Use it in your code this way
func checkMark(index: Int) {
let model = models[index]
let realm = try! Realm()
realm.asyncWrite(model) { realm, model in
model.needToUpdateOnServer = true
model.lastEditUpdate = Date()
model.read = true
}
}
HAPPY SWIFTING!
来源:https://stackoverflow.com/questions/50377554/realm-updating-data-dispatchqueue