【问题标题】:Swift closure async order of executionSwift 关闭异步执行顺序
【发布时间】:2016-10-05 17:42:49
【问题描述】:

在我的模型中,具有获取期望完成处理程序作为参数的数据的功能:

func fetchMostRecent(completion: (sortedSections: [TableItem]) -> ()) {

        self.addressBook.loadContacts({
            (contacts: [APContact]?, error: NSError?) in
            // 1
            if let unwrappedContacts = contacts {
                for contact in unwrappedContacts {

                    // handle constacts
                    ...                        
                    self.mostRecent.append(...)
                }
            }
            // 2
            completion(sortedSections: self.mostRecent)
        })
}

它正在调用另一个异步加载联系人的函数,我将完成转发到该函数

fetchMostRecent 的完成调用如下所示:

model.fetchMostRecent({(sortedSections: [TableItem]) in
    dispatch_async(dispatch_get_main_queue()) {
        // update some UI
        self.state = State.Loaded(sortedSections)
        self.tableView.reloadData()
    }
})

这有时会起作用,但通常执行顺序与我期望的不一样。问题是,有时在// 2 下的completion()// 1 下的if 范围完成之前执行。

这是为什么呢?如何确保在// 1 之后开始执行// 2

【问题讨论】:

  • 你说得对,我错过了另一个异步,我的错。那么使用局部变量,我可以首先避免这个麻烦吗?我知道我一开始尝试使用它,但我不知道该怎么做。
  • 我明白了。需要异步调用,所以我会尝试调度组。谢谢。

标签: swift asynchronous closures


【解决方案1】:

几个观察:

  1. 它将始终在 2 之前执行 1 中的内容。获得所描述行为的唯一方法是在 for 循环中执行其他操作,即其本身是异步的。如果是这种情况,您将使用调度组来解决这个问题(或重构代码以处理异步模式)。但是如果没有看到 for 循环中的内容,很难进一步评论。仅问题中的代码不应显示您描述的问题。一定是别的东西。

  2. 无关,您应该注意,在异步执行的 for 循环中更新模型对象有点危险(假设它在后台线程上运行)。更新局部变量,然后通过完成处理程序将其传回,并让调用者负责将模型更新和 UI 更新分派到主队列,这样会更安全。

  3. 在 cmets 中,您提到在 for 循环中您正在执行异步操作,并且必须在调用 completionHandler 之前完成某些操作。因此,您将使用调度组来确保仅在所有异步任务完成后才会发生这种情况。

  4. 注意,由于您在 for 循环中执行异步操作,因此您不仅需要使用调度组来触发这些异步任务的完成,而且您可能还需要创建自己的同步队列(您不应该从多个线程中更改数组)。因此,您可以为此创建一个队列。

综合起来,你最终会得到如下结果:

func fetchMostRecent(completionHandler: ([TableItem]?) -> ()) {
    addressBook.loadContacts { contacts, error in
        var sections = [TableItem]()
        let group = dispatch_group_create()
        let syncQueue = dispatch_queue_create("com.domain.app.sections", nil)

        if let unwrappedContacts = contacts {
            for contact in unwrappedContacts {
                dispatch_group_enter(group)
                self.someAsynchronousMethod {
                    // handle contacts
                    dispatch_async(syncQueue) {
                        let something = ...
                        sections.append(something)
                        dispatch_group_leave(group)
                    }
                }
            }
            dispatch_group_notify(group, dispatch_get_main_queue()) {
                self.mostRecent = sections
                completionHandler(sections)
            }
        } else {
            completionHandler(nil)
        }
    }
}

model.fetchMostRecent { sortedSections in
    guard let sortedSections = sortedSections else {
        // handle failure however appropriate for your app
        return
    }

    // update some UI
    self.state = State.Loaded(sortedSections)
    self.tableView.reloadData()
}

或者,在 Swift 3 中:

func fetchMostRecent(completionHandler: @escaping ([TableItem]?) -> ()) {
    addressBook.loadContacts { contacts, error in
        var sections = [TableItem]()
        let group = DispatchGroup()
        let syncQueue = DispatchQueue(label: "com.domain.app.sections")

        if let unwrappedContacts = contacts {
            for contact in unwrappedContacts {
                group.enter()
                self.someAsynchronousMethod {
                    // handle contacts
                    syncQueue.async {
                        let something = ...
                        sections.append(something)
                        group.leave()
                    }
                }
            }
            group.notify(queue: .main) {
                self.mostRecent = sections
                completionHandler(sections)
            }
        } else {
            completionHandler(nil)
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-03-15
    • 2015-09-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多