4

我正在使用使用该方法的网络工具包twoBlock,但我更喜欢oneBlock在我自己的代码中使用。twoBlock如果方法更好,这让我感到困惑。不知怎的,我看不到它。

有没有一种方法比另一种方法更好?


一体式方法

1个结合数据和错误的块:

-(void)oneBlock {
    [self startWithCompletionBlock:^(id obj, NSError* error) {
        if(error) {
            NSLog(@"error: %@", error);
        } else {
            NSLog(@"success: %@", obj);
        }
    }];
}

两块方法

2 个专门用于处理数据和错误的块:

-(void)twoBlocks {
    [self startWithCompletionBlock:^(id obj) {
        NSLog(@"success: %@", obj);
    } errorBlock:^(NSError* error) {
        NSLog(@"error: %@", error);
    }];
}
4

5 回答 5

4

我不认为你可以说哪一个更好。只是利弊的平衡不同。

两个块方法的主要优点是您可以更好地分离“快乐”路径的代码和错误管理的代码。(这种分离听起来类似于使用异常所提供的优点之一,但又是​​另一种野兽;实际上,catch 块允许在一个地方收集所有代码,即在您的“功能”块之外,管理一个在“功能”块中可能出现的一堆可能的错误条件,其管理通常会分散在整个块中;在上面的 2 块示例中,没有这些,因为管理错误条件的代码仍然混合在一起与您的函数的其余代码)。

另一方面,很可能在两种情况下,即成功和失败,你都想采取一些共同的行动。想想,例如,序列化一堆网络操作:当一个操作完成时,你执行下一个操作,无论是前一个操作成功还是失败完成。如果使用 2-block 方法,这显然是一种代码复制的情况。

总的来说,我不认为有很大的不同,因为您可以轻松地使用这两种方法完成您需要做的事情,但在特定情况下,一种方法比另一种更适合您的工作流程。

只是我的2美分。

于 2012-07-26T10:02:30.333 回答
1

我发现 2 块方法“更干净”。您不需要 if/else 块,因此可以更好地分离错误处理。它也少了 1 行。总体上差别不大,但它有助于保持代码更整洁、更易于阅读,仅此而已。

我认为使 2-block 更好的另一件事是错误处理会自动推到最后。我更喜欢代码采用“做所有这些事情,除非出现问题”的形式,而不是“假设出现问题!它没有?哦,继续。” 风格。也许我是个乐观主义者。无论哪种方式,我宁愿看到顶部的重要内容,以及错误处理。

于 2012-07-26T09:59:11.280 回答
1

我更喜欢#1。我认为应该由客户端代码根据发送回的 NSError 实例来决定实际错误是什么以及它在当前上下文中的含义。

在选项 #2 中,如果完成块包含的代码不只几行,例如在视图控制器中使用时很可能,那么您很有可能希望在两者中执行很多相同的完成代码无论是否发生错误(更新 UI、恢复某些状态等),都会阻塞。这将导致不必要的代码重复。

此外,如果您碰巧不关心错误情况,选项#1 的代码更少。

于 2012-07-26T10:25:04.910 回答
1

我已经确定了两块方法。优点是:

  • 它允许在需要时返回一个对象和一个错误
  • 没有订购问题,也没有一个或两个都可以调用的问题
  • 如果您将第三个变量添加到另一个回调中,事情就不会那么混乱了

在我看来,应该为多个顺序回调保留多个块。想想 UIView 动画的工作方式。

于 2012-07-26T13:55:07.580 回答
1

由于@sergio 提到的原因,我认为 oneBlock 方法更干净。它为调用者提供了更大的灵活性来管理代码路径。使用这样的回调 API,无论是否成功,都必须在回调结束时经常调用清理(或下一步)代码:

-(void)oneBlock {
    [self startWithCompletionBlock:^(id obj, NSError* error) {
        if (error) {
            NSLog(@"error: %@", error);
        } else {
            NSLog(@"success: %@", obj);
        }
        self.connection = nil;
        dispatch_async(dispatch_get_main_queue(), ^{
            [self updateUI];
        });
    }];
}

此外,如果成功块很长,则 twoBlocks 的读取效果很差:

-(void)twoBlocks {
    [self startWithCompletionBlock:^(id obj) {
        [self doSomething];
        [self doSomethingElse];

        [self setUpSomeOtherRequestWithCompletionBlock:^(id obj) {
            [self doSomething];
            [self doSomethingElse];

            NSLog(@"inside request succeeded");
        } errorBlock:^(NSError* error) {
            NSLog(@"error: %@", error);
        }];

        dispatch_async(dispatch_get_main_queue(), ^{
            [self updateUI];
        });
    } errorBlock:^(NSError* error) {
        NSLog(@"error: %@", error);
    }];
}
于 2012-07-27T20:14:42.957 回答