DispatchGroup和Realm

时间:2017-05-29 11:45:37

标签: ios swift realm grand-central-dispatch background-process

我的应用程序使用Swift 3.1,Realm 2.7.0作为数据库,并有一个后台服务,使用DispatchGroup来控制我确定的进程流。

首先,在我的ViewController中,我执行了Realm的通知系统,称为NotificationToken,使用方法addNotificationBlock检测确定对象中的任何数据变化。

在此之前,一切都很好。所有更改都会调用此块。

我已经实施了一个使用大量DispatchQueueDispatchGroup的新流程,这是一个示例:

此代码只是一个示例!不要这样做!

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运行时,其通知块上添加的对象不会更新。

谢谢!

2 个答案:

答案 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
      }
    }
  }