2017-04-24 108 views
1

我希望调度组内的代码在发生任何事情之前完成执行,实质上阻止应用程序执行任何操作,直到完成此代码。但是,我无法让调度组阻止运行中的其他代码。我已经在堆栈上尝试了几乎所有的建议,但我不知道我在做什么。调度组不阻止代码运行

我的功能:

- (void)myFunction { 

    NSString *myString = @"Hello world"; 

    dispatch_group_t group = dispatch_group_create(); 

    NSLog(@"1 entering the dispatch group"); 

    dispatch_group_enter(group); 
    [self doSomething:myString completion:^{ 
     dispatch_group_leave(group); 
     NSLog(@"2 we have left the dispatch group"); 
    }]; 
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{ 
     NSLog(@"3 notifying that the dispatch group is finished"); 
    }]; 
    NSLog(@"4 all process are complete, we are done"); 
} 

我通过日志语句要输出= 1,2,3,4

输出I通过日志语句得到= 1,4,2,3

为什么我的代码跳过调度组并在2和3之前打印4?任何关于我在做什么错误的建议表示赞赏。谢谢!

更新:

这是我doSomething方法。我的代码不断挂在dismiss呼叫。

doSomething() { 

    viewController.dismiss(animated: false completion: { [weak self] in 
     doMoreCode() 
    }) 
} 

回答

3

这里没有什么实际上阻止。 dispatch_group_notify只是说“当组完成时,运行这个。”您打算使用的工具是dispatch_group_wait。如果你想1,2,3,4,那么你的意思是这样的:

- (void)myFunction { 

    NSString *myString = @"Hello world"; 

    dispatch_group_t group = dispatch_group_create(); 

    NSLog(@"1 entering the dispatch group"); 

    dispatch_group_enter(group); 
    [self doSomething:myString completion:^{ 
     NSLog(@"2 we have left the dispatch group"); 
     dispatch_group_leave(group); 
    }]; 

    dispatch_group_wait(group, DISPATCH_TIME_FOREVER); 

    NSLog(@"3 notifying that the dispatch group is finished"); 

    NSLog(@"4 all process are complete, we are done"); 
} 

当然myFunction不能被称为在iOS上的主队列(因为它会阻止,你必须永远不会阻塞主队列)。而且它也不能在doSomething:completion:用于其完成处理程序的同一队列中调用(因为该队列将被阻止在dispatch_group_wait)。

请记住,dispatch_queue_notify只是将一个块添加到将来某个时间运行的队列中。所以有点不清楚你如何期望3和4的工作(在我的例子中,我刚刚崩溃了他们,但也许你正在寻找其他的东西)。

另一种方法是而不是阻止应用程序,并且只是安排在应该运行时运行的东西。在这种情况下,您可以使用主队列。它会是这样的:在这两个例子中

- (void)myFunction { 

    NSString *myString = @"Hello world"; 

    dispatch_group_t group = dispatch_group_create(); 

    NSLog(@"1 entering the dispatch group"); 

    dispatch_group_enter(group); 
    [self doSomething:myString completion:^{ 
     NSLog(@"2 we have left the dispatch group"); 
     dispatch_group_leave(group); 
    }]; 
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{ 
     NSLog(@"3 notifying that the dispatch group is finished"); 
    }); 
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{ 
     NSLog(@"4 all process are complete, we are done"); 
    }); 
} 

注意,我打电话dispatch_group_leave之前记录2。在这个例子中,我还注册了两个东西,在主队列中(按顺序)在组完成后运行。在这种情况下,myFunction将立即返回(所以它可以在主队列上运行),但所有内容都应按顺序打印出来。

+0

感谢您的回应!我用dispatch_group_wait''得到的问题是它保持死锁。有什么办法解决这个问题,或者只是暂停一下? – user3353890

+0

我喜欢使用'''dispatch_group_wait''',因为在继续之前我需要确保doSomething''完成,但它对我保持死锁。它只是挂起,所以我将不得不调查为什么会发生。 – user3353890

+1

@ user3353890您的死锁,因为'dispatch_group_leave'必须从与dispatch_group_wait不同的线程调用。不知道doSomething实际上做了什么,很难确定。用更多的细节更新你的问题。 – rmaddy

1

假设doSomething异步运行,您可以等待该组,但最好是接受异步模式,例如,允许myFunction立即返回,而是提供自己的完成处理程序,以这种方法:

- (void)myFunctionWithCompletion:(void (^)())completion { 
    NSString *myString = @"Hello world"; 

    dispatch_group_t group = dispatch_group_create(); 

    NSLog(@"1 entering the dispatch group"); 

    dispatch_group_enter(group); 
    [self doSomething:myString completion:^{ 
     dispatch_group_leave(group); 
     NSLog(@"2 we have left the dispatch group"); 
    }]; 
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{ 
     NSLog(@"3 notifying that the dispatch group is finished"); 
    }); 
} 

并使用它像这样:

[self myFunctionWithCompletion:^{ 
    NSLog(@"4 all process are complete, we are done"); 
}]; 

// note, it's not done when it gets here, though, because it's asynchronous 

显然,在上面的例子中,调度组完全是多余的,但我假设你正在执行多个异步任务,这就是为什么你引入了调度组。如果真的只是这一个异步任务,你只需要:

- (void)myFunctionWithCompletion:(void (^)())completion { 
    NSString *myString = @"Hello world"; 

    [self doSomething:myString completion:^{ 
     NSLog(@"The asynchronous doSomething is done"); 
     completion(); 
    }]; 
} 
+0

我喜欢使用多个通知和完成处理程序。我唯一的问题是我需要确保''''doSomething'''在继续之前完成。我担心我会在某处调用''myFunction'',然后''''myFunction'''后面的代码将在'''doSomething'''完成之前执行。 – user3353890

+0

我可以理解想要在继续​​之前“确保doSomething”完成的吸引力,但我认为这是一个根本上有缺陷的方法。如果你看看苹果的API,他们遵循的规则是“如果一个方法可能需要超过几个毫秒,使其异步并提供完成处理程序”。他们非常正确地在我的脑海中大量地删除了任何阻止方法的API。如果你担心“myFunction”之后的代码,你就像我们一直在处理所有其他异步API一样处理它:将相关代码放入完成块中。 – Rob

+0

我毫不犹豫地建议它,但其他可接受的模式是使用promises,la [PromiseKit](http://promisekit.org)或RXPromise。我认为这是过度的,在深入研究这些其他模式之前,真正适应“具有完成处理程序的异步方法”模式是一种重要的iOS编程模式,但为了完整起见,我提到它。 – Rob