调度块 return 太早 (Swift)

dispatch blocks return too early (Swift)

我正在尝试确保在继续主线程之前完成我的云访问。我从警报操作中调用 downloadRecordsWithCompletion,所以我在一个封闭空间中。

        self.downloadRecordsWithCompletion() {
            error in

            println("out of alert")
            println("raceIdentities.count = \(raceIdentities.count)")
            println("raceTeams.count = \(raceTeams.count)")
            println("raceTasks.count = \(raceTasks.count)")

            self.misc()

        }

这里是调用的代码:

func downloadRecordsWithCompletion(completion: (error: NSError?) -> Void) {
    dispatch_async(GlobalUserInitiatedQueue) {
        var storedError: NSError!
        var downloadGroup = dispatch_group_create()

        dispatch_group_enter(downloadGroup)
        self.cloudReadRaceIdentities(self.isMonitor)
        dispatch_group_leave(downloadGroup)

        dispatch_group_enter(downloadGroup)
        self.cloudReadParameters()
        dispatch_group_leave(downloadGroup)

        dispatch_group_enter(downloadGroup)
        self.cloudReadCheckpoints()
        dispatch_group_leave(downloadGroup)

        dispatch_group_enter(downloadGroup)
        self.cloudReadTeams()
        dispatch_group_leave(downloadGroup)

        dispatch_group_enter(downloadGroup)
        self.cloudReadTasks()
        dispatch_group_leave(downloadGroup)

/*
        dispatch_group_enter(downloadGroup)
        self.cloudReadRaceIdentities(self.isMonitor)
        self.cloudReadParameters()
        self.cloudReadCheckpoints()
        self.cloudReadTeams()
        self.cloudReadTasks()
        dispatch_group_leave(downloadGroup)
*/

        dispatch_group_wait(downloadGroup, DISPATCH_TIME_FOREVER)

        dispatch_async(GlobalMainQueue) {
            //if let completion = completion {
                completion(error: storedError)
            //}
        }
    }
}

不管我怎么试,它总是在命中时抛出"fatal error: unexpectedly found nil while unwrapping an Optional value"

println("raceIdentities.count = \(raceIdentities.count)")

因为从这一行调用的代码:

self.cloudReadRaceIdentities(self.isMonitor)

还没有发生。

我尝试了注释掉的代码(没有成功)并且还更改了这一行:

dispatch_async(GlobalUserInitiatedQueue) {

至此

dispatch_sync(GlobalUserInitiatedQueue) {

我也将 println 语句移到了外壳之外,结果相同。

我的大部分信息来自 raywenderlich.com 他为 Swift 编写的 Grand Central Dispatch 教程,但显然我遗漏了一些东西。

有什么想法吗?

您必须:

  • 使您的 reader 函数同步。然后你也可以删除所有 dispatch_group 东西(反正你现在拥有它什么都不做)
  • 向您的 reader 函数添加一个完成处理程序,您在其中保留 dispatch_group

我建议使用第一种方法,它看起来像这样(在使 reader 函数同步之后):

func downloadRecordsWithCompletion(completion: (error: NSError?) -> Void) {
    dispatch_async(GlobalUserInitiatedQueue) {

        self.cloudReadRaceIdentities(self.isMonitor)
        self.cloudReadParameters()
        self.cloudReadCheckpoints()
        self.cloudReadTeams()
        self.cloudReadTasks()

        dispatch_async(GlobalMainQueue) {
            completion(error: nil)
        }
    }
}

第二种方法看起来像这样(在向 reader 函数添加完成处理程序参数之后):

func downloadRecordsWithCompletion(completion: (error: NSError?) -> Void) {
    dispatch_async(GlobalUserInitiatedQueue) {
        let downloadGroup = dispatch_group_create()

        dispatch_group_enter(downloadGroup)
        self.cloudReadRaceIdentities(self.isMonitor) {
            dispatch_group_leave(downloadGroup)
        }

        dispatch_group_enter(downloadGroup)
        self.cloudReadParameters() {
            dispatch_group_leave(downloadGroup)
        }

        dispatch_group_enter(downloadGroup)
        self.cloudReadCheckpoints() {
            dispatch_group_leave(downloadGroup)
        }

        dispatch_group_enter(downloadGroup)
        self.cloudReadTeams() {
            dispatch_group_leave(downloadGroup)
        }

        dispatch_group_enter(downloadGroup)
        self.cloudReadTasks() {
            dispatch_group_leave(downloadGroup)
        }

        dispatch_group_wait(downloadGroup, DISPATCH_TIME_FOREVER)

        dispatch_async(GlobalMainQueue) {
            completion(error: nil)
        }
    }
}

哦,这也可能行不通(忘了上面这个),因为只有一组,但可以保留多个点。所以你可能想使用一个 dispatch_semaphore 等待直到它被发出 n 次这样的信号:

func downloadRecordsWithCompletion(completion: (error: NSError?) -> Void) {
    dispatch_async(GlobalUserInitiatedQueue) {
        let semaphore = dispatch_semaphore_create(5)

        self.cloudReadRaceIdentities(self.isMonitor) {
            dispatch_semaphore_signal(semaphore)
        }

        self.cloudReadParameters() {
            dispatch_semaphore_signal(semaphore)
        }

        self.cloudReadCheckpoints() {
            dispatch_semaphore_signal(semaphore)
        }

        self.cloudReadTeams() {
            dispatch_semaphore_signal(semaphore)
        }

        self.cloudReadTasks() {
            dispatch_semaphore_signal(semaphore)
        }

        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)

        dispatch_async(GlobalMainQueue) {
            completion(error: nil)
        }
    }
}

但我仍然建议让您同步读取函数,因为您的方法中已经是异步的