web-dev-qa-db-ja.com

多くのネットワーク要求を行うiOSアプリケーションに最適なアーキテクチャは?

開発中の大きなアプリのリクエストアーキテクチャへのアプローチを再考しているところです。私は現在ASIHTTPRequestを使用して実際にリクエストを作成していますが、さまざまなビューコントローラーでさまざまなアクションを実行した結果としてさまざまなタイプのリクエストが必要になるため、これらのリクエストを整理する最適なシステムを構築しようとしています。

私は現在、アプリデリゲートによって保持されるシングルトンの「リクエスター」を構築しており、リクエストの作成が必要であることを示すNSNotificationをリッスンしています。リクエストを作成し、レスポンスをリッスンし、レスポンスデータを含む新しいNSNotificationを送信します。これは私の問題のほとんどを解決しますが、失敗した要求または同じシングルトンリクエスタへの同時要求をエレガントに処理しません。

IOSアプリでさまざまな種類のリクエストを行うための明確なOOアーキテクチャを考案することで、誰もが成功していますか?

50
kevboh

いくつかのアプローチを試した後、これは私に優れた結果をもたらし、文書化、理解、維持、および拡張が容易な1つのアーキテクチャです。

  • ネットワーク接続を処理する単一のオブジェクトがあります。それを「ネットワークマネージャー」と呼びましょう。通常、このオブジェクトはシングルトンです( Matt GallagherのCocoaシングルトンマクロ を使用して作成)。
  • ASIHTTPRequest(私はいつもそうですが、素晴らしいAPI)を使用しているので、ネットワークマネージャー内にASINetworkQueue ivarを追加します。ネットワークマネージャーをそのキューのデリゲートにします。
  • アプリが必要とするネットワーク要求の種類ごとにASIHTTPRequestのサブクラスを作成します(通常、バックエンドごとにRESTインタラクションまたはSOAPエンドポイント)。これには別の利点があります。 (詳細は以下を参照してください:)
  • コントローラーの1つが何らかのデータ(refresh、viewDidAppearなど)を必要とするたびに、ネットワークマネージャーは必要なASIHTTPRequestサブクラスのインスタンスを作成し、それをキューに追加します。
  • ASINetworkQueueは帯域幅の問題を処理します(3G、Edge、GPRS、またはWifiのいずれであるかに応じて、より多くの帯域幅があり、より多くのリクエストを処理できます)。これはキューによって行われます。これはクールです(少なくとも、これはこのキューが行うことの1つです。私が誤解していないことを願っています:)。
  • リクエストが終了または失敗すると、ネットワークマネージャーが呼び出されます(ネットワークマネージャーがキューのデリゲートであることを忘れないでください)。
  • ネットワークマネージャーは、各リクエストの結果をどうするかについてスクワットを知りません。したがって、リクエストでメソッドを呼び出すだけです!リクエストはASIHTTPRequestのサブクラスであるため、リクエストの結果を管理するコードを置くだけでよいことに注意してください(通常、JSONまたはXMLの実際のオブジェクトへの逆シリアル化、他のネットワーク接続のトリガー、コアデータストアの更新など)。リクエストクラス全体で共通の名前を持つポリモーフィックメソッドを使用して、コードを各個別のリクエストサブクラスに配置すると、IMHOのデバッグと管理が非常に簡単になります。
  • 最後に、通知を使用して、興味深いイベントについて上記のコントローラーに通知します。デリゲートプロトコルを使用することは良い考えではありません。アプリでは通常、ネットワークマネージャーと通信する多くのコントローラーがあり、通知はより柔軟です(同じ通知に複数のコントローラーが応答するなど)。

とにかく、これは私がしばらくそれをやってきた方法であり、率直に言ってそれはかなりうまくいきます。システムを水平方向に拡張し、必要に応じてASIHTTPRequestサブクラスを追加できます。ネットワークマネージャーのコアはそのまま残ります。

それが役に立てば幸い!

69

これが私が一般的に行う方法です。私も、ネットワークリクエストを行うために使用されるシングルトンオブジェクトを持っています。リクエストを頻繁に行う必要がある場合、通常はAFNetworkingを使用してリクエストを行うため、AFHTTPRequestOperations(またはAFJSONRequestOperations)を受け入れるNSOperationQueueがあります。これらについては、要求の成功または失敗時に実行されるcompletionBlockおよびfailureBlockプロパティがあります。私のシングルトンオブジェクトには、特定のネットワーク要求を開始するメソッドがあり、そのメソッドへのパラメーターとして、メソッドで定義されたブロックに渡すことができる成功および失敗のブロックを含めます。このようにして、アプリケーション全体がネットワーク要求を行うことができ、その時点でのアプリケーションのスコープは、メソッドに渡されるブロック内のシングルトンで使用できます。たとえば...(ARCを使用)

        @implementation NetworkManager

    -(void)makeRequestWithSuccess:(void(^)(void))successBlock failure:(void(^)(NSError *error))failureBlock

    {
        NSURL *url = [NSURL URLWithString:@"some URL"];

        NSURLRequest *request = [NSURLRequest requestWithURL:url];

        AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:request];

        [op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
            [responseObject doSomething];

            if (successBlock)
                dispatch_async(dispatch_get_main_queue(), successBlock);

        } failure:^(AFHTTPRequestOperation *operation, NSError *error) {

            if (failureBlock)
                dispatch_async(dispatch_get_main_queue(), ^{
                    failureBlock(error);
                });
        }];

        [self.operationQueue addOperation:op];
    }
@end

また、成功ブロックに、渡す必要のあるパラメーターを常に取得させることができます。

1
Jacob

STNetTaskQueue を試してみてください。これにより、リクエストを再利用可能にして、保守可能にすることができます。

0
Kevin

fully-loaded プロジェクトは良い読み物です。

0
ohho