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

Posted

技术标签:

【中文标题】多个完成块完成后执行的函数【英文标题】:Function that executes after multiple completion block has finished 【发布时间】:2016-09-20 08:03:32 【问题描述】:

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

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

【问题讨论】:

How do I know all my tasks in Grand Central Dispatch finished?的可能重复 我不确定这是否重复,因为该示例使用 GCD 而我的下载代码没有使用它(无论如何从我的级别)。它的下载代码是带有回调的标准 Firebase 查询块。所以我不确定如何在我的情况下正确整合它。 我会使用 NSNotificationCenter 并为每个人调用 allDataDownloadComplete()... 然后在 allDataDownloadComplete 中检查所有标志是否为真,然后才能执行。我还没有找到另一种方法来做到这一点 - 标志也不错 - 它们往往会在以后再次派上用场:) 如果是async,那么可以使用dispatch_group,没关系,只需要在completion处放置group exit即可 【参考方案1】:

最好的选择是使用 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
    

【讨论】:

【参考方案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 知识或使用函数式反应式编程将使您的工作更轻松从长远来看。

【讨论】:

以上是关于多个完成块完成后执行的函数的主要内容,如果未能解决你的问题,请参考以下文章

并行执行多个 AJAX 请求,并在所有请求完成后运行一个函数

each() 函数中的多个 ajax 调用.. 然后在所有这些都完成后执行一些操作?

在目标c中使用完成块完成方法后如何执行另一种方法?

如何在不使用完成块的情况下在动画后执行代码?

我的 animatewithduration,完成块只执行一次

在执行下一个代码块之前等待多个 RxJS 调用