1

手に負えなくなったいくつかのコードをクリーンアップしようとしています。ユーザーがアクティビティ インジケーターのスピンを見つめて待っている間に、Parse や Facebook、おそらく Core Data などのいくつかのリモート API と対話する必要がある状況がよくあります。

私の要件は次のとおりです。

  • もちろん、遅いものはすべてバックグラウンドスレッドにある必要があります
  • サイレントまたは無視されたエラー メッセージはありません。
  • ユーザー (彼がびっくりしないように) と私自身 (サポートの電話がかかってきて、何が問題だったのかを突き止める必要がある場合) の両方を、できる限り役立つエラー メッセージで支援したいと考えています。
  • ロジックを保守可能にしたい。以下のようなチャンクは、循環的複雑度が非常に速く上昇し、適切に処理されないと、特にマルチスレッドが追加された場合、悪夢のような作業になります。

私が現在使用しているパターンは次のとおりです。

- (void)sampleFacebookProcessingCall
{
    [self.spinner startAnimating];
    [FBRequestConnection startForMeWithCompletionHandler:^(FBRequestConnection *connection, id result, NSError *facebookRequestError)
    {
        // we're back in main queue, let's return to a secondary queue
        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{

            // don't want do display the actual error to the user
            NSString *errorMessage;
            NSError *error;
            @try {
                if (facebookRequestError) {
                    errorMessage = @"Could not connect to Facebook, please try again later.";
                    return;
                }

                [Helper someParseCall:&error];
                if (error) {
                    errorMessage = @"The operation could not be completed, please try again later. Code: FOO1";
                    return;
                }

                [Helper someOtherParseCall:&error];
                if (error) {
                    errorMessage = @"The operation could not be completed, please try again later. Code: FOO2";
                    return;
                }

                [...]
            }
            @finally {
                dispatch_async(dispatch_get_main_queue(), ^{
                    [self.activityIndicator stopAnimating];
                    if (errorMessage) {
                        // there might be half-baked state out there afer the error
                        [self cleanupResources];
                        [UIHelper displayErrorAlertViewWithMessage:errorMessage];
                    }
                });
            }
         });
     }];
 }

さて、エラーが発生したときにフローをエスケープするには、明らかに異なるパターンがあります。戻り値を伴う @try/@finally パターン (クリーンアップ ラベルを使用した古い学校の goto と同じ考え方) は 1 つの方法です。別の方法は、エラー オブジェクトを「続行する必要がある」変数として使用し、次のようにすることです。

if (!error) {
    doStuff(&error)
}
if (!error) {
[...]

GCD の追加により、重い作業が常にバックグラウンドで実行され、エラーがメイン スレッドでのみ報告されることを確認する必要があるため、少し複雑になります。すべての API のライブラリは少し異なる方法で処理を行うため、メイン スレッドで実行されるブロックのみを受け入れる Facebook のようなものがあり、必要に応じてブロック呼び出しを実行できるようにする Parse と織り交ぜる必要があります。

誰かがよりクリーンなアプローチを思いついたのではないかと思っています。これは、ほとんどのアプリが遅かれ早かれ対処することになるものであり、車輪を再発明する必要はないと思います.

4

0 に答える 0