如何在以下或类似情况下避免回调地狱,
[self saveSomethingToTheServerWithCompletion:^(BOOL saveSucceeded) {
dispatch_async(dispatch_get_main_queue(), ^{
[self dismissViewControllerAnimated:YES completion:^{
dispatch_async(dispatch_get_main_queue(), ^{
if (saveSucceeded) {
[self showAlertControllerWithTitle:@"Message" message:@"Save successful."];
} else {
[self showAlertControllerWithTitle:@"Message" message:@"Save failed."];
}
});
}];
});
}];
我的理解是dismissViewControllerAnimated:completion:
和showAlertControllerWithTitle:message:
必须在主线程上执行。
答案 0 :(得分:1)
这个问题相当含糊,所以我正在猜测你的问题。我唯一能想到的是你对嵌套调用不满意。您可以在一定程度上整理方法。例如你知道总是需要在主线程上显示警告,所以将主线程代码移动到你的警报方法:
[self saveSomethingToTheServerWithCompletion:^(BOOL saveSucceeded) {
dispatch_async(dispatch_get_main_queue(), ^{
[self dismissViewControllerAnimated:YES completion:^{
NSString *message = saveSucceeded ? @"Save successful." : @"Save failed.";
[self showAlertControllerWithTitle:@"Message" message:message];
}];
});
}];
- (void)showAlertControllerWithTitle:(NSString *)title message:(NSString *)message {
dispatch_async(dispatch_get_main_queue(), ^{
//Show alert;
}
}
此外,您可以考虑从dismissViewControllerAnimated
调用中删除完成块。即你的警报显示真的取决于视图控制器是否已被解雇?
[self saveSomethingToTheServerWithCompletion:^(BOOL saveSucceeded) {
dispatch_async(dispatch_get_main_queue(), ^{
NSString *message = saveSucceeded ? @"Save successful." : @"Save failed.";
[self showAlertControllerWithTitle:@"Message" message:message];
[self dismissViewControllerAnimated:YES completion:nil];
});
}];
最终,有时你只需要嵌套回调。这没有什么不妥。
编辑:我还用三元代替了你的if语句而没有真正考虑它。不确定你是否算作“回调地狱”。
答案 1 :(得分:0)
您可以尝试这样的事情
[self saveSomethingToTheServerWithCompletion:^(BOOL saveSucceeded) {
dispatch_async(dispatch_get_main_queue(), ^{
NSString *strMsg = saveSucceeded ? @"Save successful." : @"Save failed.";
UIAlertAction *okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
dispatch_async(dispatch_get_main_queue(), ^{
[self dismissViewControllerAnimated:YES completion:^{
}];
});
}];
[self showAlertWithTitle:@"Message" message:strMsg actions:@[okAction]];
});
}];
- (void)showAlertWithTitle:(NSString * _Nonnull)title message:(NSString * _Nonnull)msg actions:(NSArray * _Nonnull)actions {
UIAlertController *alertVC = [UIAlertController alertControllerWithTitle:title message:msg preferredStyle:UIAlertControllerStyleAlert];
for (UIAlertAction *action in actions) {
[alertVC addAction:action];
}
[self presentViewController:alertVC animated:true completion:nil];
}
因此,在回调时,它将显示带有消息的警报,并且在ok按钮上,顶部警报将解除并且还将关闭所呈现的视图控制器。所以它将在主线上。
答案 2 :(得分:0)
你不必在主线程中使用回调包装dismissViewControllerAnimated:因为它已经在主线程中,也试图避免重复的代码:
View inflate = View.inflate(getContext(), R.layout.dialog_add_url, null);
dialogViewHolder = new DialogViewHolder(inflate);