1

GCD 和积木非常方便。但是当我爱上它时,我发现发生了不好的事情。看看下面的这些代码:

[self functionA:^(BOOL success) {
  if (success) {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
      [self functionB:^(NSError *error) {
        if (error != nil) {
          dispatch_async(dispatch_get_main_queue(), ^(void) {
            [self functionC:^(id result) {
              if (result) {
                [self functionD:^(BOOL success) {
                  if (success) {
                    [self DoSomething];
                  }
                }];
              }
            }];
          });
        }
      }];
    });
  }
}];

疯狂的?是的。我遇到了这个麻烦。

有人有避免这样的嵌套块的经验吗?

编辑:

多谢你们。确切地说,我们有更优雅的方法来做到这一点。如:

  • 预先声明块
  • 使子块成为独立的功能

但我期望的是一个通用的解决方案。也许是这样的:(下面的伪代码)

functionA.flat.success = [self functionB];
functionB.flat.isntnil = [self functionC];
functionB.flat.error = {};
functionC.flat.isntnil = [self functionD];
[flat call:functionA];
4

1 回答 1

5

好吧,我没有费心匹配你的右括号云,但这里是一个简单的使用 return 的尝试,你也可以在块内自由使用它并稍微减少嵌套:

[self functionA:^(BOOL success) {
  if (!success)
    return;

  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
    [self functionB:^(NSError *error) {
      if (!error)
        return;

      dispatch_async(dispatch_get_main_queue(), ^(void) {
        [self functionC:^(id result) {
          if (!result)
            return;

          [self functionD:^(BOOL success) {
            if (!success)
              return;

            [self DoSomething];
          }];
        }];
      });
    }];
  });
}];

此外,没有人强迫您编写块inline,您可以在之前将它们声明为普通变量并在以后使用它们。事实上,如果你的 API 对其用户宽容,并且允许重复调用,即使不需要做任何工作,在你能够重用它们之前声明块:

- (void)foo:(Bar*)bar
{
    // Prepare the success handler.
    void (^successBlock)(Bar*) = ^(Bar *bar) {

        [[NSNotificationCenter defaultCenter]
            postNotificationName:@"barUpdated"
                          object:bar];
    };

    if (!bar.didAlreadyFetchStuff) {
        [self wellYouBetterFetchSomething:bar withSuccess:successBlock];
    } else {
        // Oh, fake we already did the work.
        successBlock(bar);
    }
}

每当我看到嵌套级别太高时,我都会将内部块作为类中的普通方法并简单地在块内调用它们。效果是一样的,但是看起来干净多了,而且它允许你为每个方法使用appledoc或其他文档工具,而不是希望理解嵌套的无文档块的混乱。

只有当你允许它变得疯狂时,它才会变得疯狂。

于 2013-08-19T11:37:16.197 回答