多个完成块完成后执行的函数

时间:2016-09-20 08:03:32

标签: ios swift completionhandler

我有一个功能,我想只在两个完成块完成后执行(并且无法告诉哪一个先完成)。以下是我的尝试。但是,它非常混乱,如果我有三个或更多的完成块我想等待,我会到处都有标记。我想知道是否有一种更漂亮的方式。

class TestClass: UIViewController {
    var blockOneComplete = false
    var blockTwoComplete = false

    func blockOneDownloadImageDescription(completion:()->Void) {
        downloadAsyncWithCompletion {
            blockOneComplete = true 
            if self.blockTwoComplete == true {
                self.allDataDownloadCompleted()
            } else {
                // Do nothing and wait for block Two to complete
            }
        }
    }

    func blockTwoDownloadImageData(completion:()->Void) {
        downloadAsyncWithCompletion {
            blockTwoComplete = true 
            if self.blockOneComplete == true {
                self.allDataDownloadCompleted()
            } else {
                // Do nothing and wait for block One to complete
            }
        }
    }

    func allDataDownloadComplete() {
        // Execute this funciton after all Async Download has complete
    }
}

- 更新最终结果 - 事实证明,本网站概述的内容正是我所需要的 Using dispatch groups to wait for multiple web services

我认为这不是评论中提到的SO问题的重复,因为最终解决方案包括dispatch_group_enter和dispatch_group_leave

2 个答案:

答案 0 :(得分:3)

最好的选择是使用dispatch_group

class TestClass: UIViewController {

    var group : dispatch_group_t = dispatch_group_create()

    override func viewDidLoad() {
        super.viewDidLoad()
        dispatch_group_notify(group, dispatch_get_main_queue()) { 
            allDataDownloadComplete()
        }
    }

    func blockOneDownloadImageDescription(completion:()->Void) {
        dispatch_group_enter(group)
        downloadAsyncWithCompletion {
            dispatch_group_leave(group)
        }
    }

    func blockTwoDownloadImageData(completion:()->Void) {
        dispatch_group_enter(group)
        downloadAsyncWithCompletion {
            dispatch_group_leave(group)
        }
    }

    func allDataDownloadComplete() {
        // Execute this funciton after all Async Download has complete
    }
}

答案 1 :(得分:2)

如果您不想管理标记,则需要使用dispatch_group或使用RxSwift等功能性反应式编程库来实现它。

但是,您只需使用一个计数器标记即可进行函数调用,如果是另一个NSNotification则使用ViewController

在我的一个项目中,我需要确保在调用某个函数之前完成4个completion block中的至少3个。我是这样做的:

class TestClass: UIViewController {
    var numberOfBlockCompleted = 0

    func blockOneDownloadImageDescription(completion:()->Void) {
        downloadAsyncWithCompletion {
            numberOfBlockCompleted += 1 
            self.allDataDownloadCompleted()
        }
    }

    func blockTwoDownloadImageData(completion:()->Void) {
        downloadAsyncWithCompletion {
            numberOfBlockCompleted += 1 
            self.allDataDownloadCompleted()
        }
    }

    func blockThreeDownloadImageDesc(completion:()->Void) {
        downloadAsyncWithCompletion {
            numberOfBlockCompleted += 1
            self.allDataDownloadCompleted()
        }
    }


    func allDataDownloadComplete() {
        if numberOfBlockCompleted == 3 {
            //do something
        }
    }
}

在我看来,它在很大程度上取决于应用程序的复杂程度。如果只是一两个部分,一个标志就足够了。但是,如果应用程序主要依赖于链接网络呼叫和从不同服务器获取需要等待一个或另一个像活动股票应用程序完成,那么强大的GCD知识或使用功能性反应编程将使您的工作更容易长期运行。