如何在iOS中避免回调地狱?

时间:2017-03-23 04:57:34

标签: ios objective-c callback

如何在以下或类似情况下避免回调地狱,

[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:必须在主线程上执行。

3 个答案:

答案 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);