4

私はこのアプローチを使用するネットワーク キットを使用していますが、自分のコードで を使用することを好みます。アプローチが優れている場合、これは私を混乱させます。どういうわけか私はそれを見ません。twoBlockoneBlocktwoBlock

あるアプローチが他のアプローチよりも優れている方法はありますか?


oneBlock アプローチ

データとエラーを組み合わせた 1 つのブロック:

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

twoBlockアプローチ

データとエラーの処理専用の 2 つのブロック:

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

5 に答える 5

4

どちらが優れているとは言えないと思います。メリットとデメリットのバランスが違うだけです。

2 つのブロック アプローチの主な利点は、"ハッピー" パスのコードとエラー管理のコードをより適切に分離できることです。(この分離は、例外の使用によって提供される利点の 1 つに似ていますが、別の獣です。実際、catch ブロックを使用すると、1 つの場所、つまり「機能」ブロックの外側に、すべてのコードを管理することができます。 「機能」ブロック内で発生する可能性があり、通常はその管理がブロック全体に散らばっている可能性のある一連のエラー状態; 上記の 2 つのブロックの例では、エラー状態を管理するコードがまだ混在しているように見えるため、これはありません。関数の残りのコードと一緒に)。

一方、成功と失敗の両方の場合に、何らかの共通のアクションを実行したい場合もよくあります。たとえば、一連のネットワーク操作をシリアル化することを考えてみてください。1 つの操作が完了すると、前の操作が成功または失敗して完了したときに、次の操作を実行します。これは明らかに、2 ブロック アプローチを使用している場合にコードの複製が発生するケースです。

全体として、必要なことは両方のアプローチで簡単に実行できるため、大きな違いはないと思いますが、特定のケースでは、一方のアプローチが他方よりもワークフローに適している場合があります。

ちょうど私の2セント。

于 2012-07-26T10:02:30.333 に答える
1

2 ブロック アプローチに落ち着きました。利点は次のとおりです。

  • 必要な場合に備えて、オブジェクトとエラーを返すことができます
  • 順序や、どちらかまたは両方を呼び出すことができるかどうかは問題ではありません
  • 別のコールバックに 3 番目の変数を追加した場合、物事はそれほど面倒ではありません

私の考えでは、複数の連続したコールバックのために複数のブロックを予約する必要があります。UIView アニメーションの仕組みを考えてみてください。

于 2012-07-26T13:55:07.580 に答える
1

2ブロックのアプローチが「よりクリーン」だと思います。その if/else ブロックは必要ないため、エラー処理をより適切に分離できます。また、1行少ないです。全体的に大きな違いはありませんが、コードを少し整理して読みやすくするのに役立ちます。それだけです。

2-block のもう 1 つの改善点は、エラー処理が自動的に最後までプッシュされることです。私は、「何かがうまくいかなかったと仮定して、そうではなかったのですか?ああ、続けてください」という形式よりも、「何かがうまくいかなかった場合を除いて、このすべてのことを行う」形式のコードを好みます。スタイル。多分私は楽観主義者です。いずれにせよ、重要なものは一番上に表示し、エラー処理は邪魔にならないようにしたいと思います。

于 2012-07-26T09:59:11.280 に答える
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 に答える
1

私は#1が好きです。送り返される NSError インスタンスに基づいて、実際のエラーが何であり、現在のコンテキストでそれが何を意味するかを判断するのは、クライアント コードに任せるべきだと思います。

オプション #2 では、完了ブロックに数行以上のコードが含まれている場合 (たとえばビュー コントローラーで使用される可能性が高い)、2 つのブロックで同じ完了コードを多数実行する可能性が高くなります。エラーが発生したかどうかに関係なくブロックします (UI の更新、状態の復元など)。これにより、不要なコードの重複が発生します。

また、エラーケースを気にしない場合、オプション#1はコードが少なくなります。

于 2012-07-26T10:25:04.910 に答える