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];
          }];
        }];
      });
    }];
  });
}];

また、ブロックをインラインで書くことを強制する人は誰もいません。前に通常の変数として宣言し、後で使用することができます。実際、 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 に答える