我的应用程序使用Swift
3.1,Realm
2.7.0作为数据库,并有一个后台服务,使用DispatchGroup
来控制我确定的进程流。
首先,在我的ViewController
中,我执行了Realm
的通知系统,称为NotificationToken
,使用方法addNotificationBlock
检测确定对象中的任何数据变化。
在此之前,一切都很好。所有更改都会调用此块。
我已经实施了一个使用大量DispatchQueue
和DispatchGroup
的新流程,这是一个示例:
此代码只是一个示例!不要这样做!
DispatchQueue.global(qos: .background).async {
autoreleasepool {
//Other stuff...
let id = 1337
let dispatchGroup = DispatchGroup()
dispatchGroup.enter()
DispatchQueue(label: "Process").sync {
let foo = Bar()
foo.progress = { newValueInt in
let realm = try! Realm()
try! realm.write {
realm
.object(ofType: Some.self, forPrimaryKey: id)
.someValue = newValueInt
}
}
foo.completed = {
dispatchGroup.leave()
}
foo.doSomethingAsync()
}
dispatchGroup.notify(queue: DispatchQueue.global(qos: .background)) {
//Process completed.
}
}
}
问题是:addNotificationBlock
未调用,并且在方法Bar.progress
运行时,其通知块上添加的对象不会更新。
谢谢!
答案 0 :(得分:4)
这是一个完整的应用,它使用您的代码,填写您没有提供的空白,并正确调用通知块:
import UIKit
import RealmSwift
class Bar {
var progress: ((Int) -> Void)?
var completed: (() -> Void)?
func doSomethingAsync() {
for delay in 1...100 {
// Span these 100 updates over 10 seconds
DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + Double(delay) / 10) {
self.progress?(delay)
if delay == 100 {
self.completed?()
}
}
}
}
init() {}
}
class Some: Object {
dynamic var id = 0
dynamic var someValue = 0
override static func primaryKey() -> String? {
return "id"
}
}
func bgTask() {
DispatchQueue.global(qos: .background).async {
autoreleasepool {
//Other stuff...
let id = 1337
let dispatchGroup = DispatchGroup()
dispatchGroup.enter()
DispatchQueue(label: "Process").sync {
let foo = Bar()
foo.progress = { newValueInt in
let realm = try! Realm()
try! realm.write {
realm
.object(ofType: Some.self, forPrimaryKey: id)!
.someValue = newValueInt
}
}
foo.completed = {
dispatchGroup.leave()
}
foo.doSomethingAsync()
}
dispatchGroup.notify(queue: .global(qos: .background)) {
//Process completed.
}
}
}
}
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var notificationToken: NotificationToken!
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
_ = try? FileManager.default.removeItem(at: Realm.Configuration.defaultConfiguration.fileURL!)
let realm = try! Realm()
let some = Some()
try! realm.write {
some.id = 1337
realm.add(some)
}
notificationToken = some.addNotificationBlock { change in
switch change {
case .change(let properties):
print(properties)
case .error(let error):
print("An error occurred: \(error)")
case .deleted:
print("The object was deleted.")
}
}
bgTask()
return true
}
}
此日志(为简洁而截断):
[RealmSwift.PropertyChange(name: "someValue", oldValue: Optional(0), newValue: Optional(1))]
[RealmSwift.PropertyChange(name: "someValue", oldValue: Optional(1), newValue: Optional(2))]
[RealmSwift.PropertyChange(name: "someValue", oldValue: Optional(2), newValue: Optional(3))]
[RealmSwift.PropertyChange(name: "someValue", oldValue: Optional(3), newValue: Optional(4))]
[RealmSwift.PropertyChange(name: "someValue", oldValue: Optional(4), newValue: Optional(5))]
...
[RealmSwift.PropertyChange(name: "someValue", oldValue: Optional(98), newValue: Optional(97))]
[RealmSwift.PropertyChange(name: "someValue", oldValue: Optional(97), newValue: Optional(100))]
答案 1 :(得分:-1)
解决方案非常简单,您只需要在主线程上运行更新。
foo.progress = { newValueInt in
DispatchQueue.main.sync {
let realm = try! Realm()
try! realm.write {
realm
.object(ofType: Some.self, forPrimaryKey: id)
.someValue = newValueInt
}
}
}