1

XMLRESTWebサービスを照会する小さなiOSアプリを書いています。使用されているネットワークフレームワークはAFNetworkingです。

状況

Webサービスをクエリするために、AFHTTPClientをサブクラス化しました。

@interface MyApiClient : AFHTTPClient

実装では、それをシングルトンとして利用できるようにします。

+ (MyApiClient *)sharedClient {
    static MySharedClient *_sharedClient = nil;
    static dispatch_once_t oncePredicate;
    dispatch_once(&oncePredicate, ^{
        _sharedClient = [[self alloc] initWithBaseUrl:[NSUrl URLWithString:@"http://url.to.the.webservice"]];
    });

    return self;
} 

initWithBaseURLで、AFNetworkingにXMLコンテンツを期待するように指示します。

[self registerHTTPOperationClass:[AFXMLRequestOperation class]];

これで、ViewControllerからシングルトンでgetPatchを呼び出し、成功ブロックで返されたXMLの解析を開始できます。次に、ViewControllerのNSXMLParserDelegateメソッドで、関心のあるXMLの部分を選択し、それを使用して処理を行うことができます。

問題

HTTPClientシングルトンに、Webサービスに関連するすべてを処理し、XMLの代わりにデータモデルまたはモデルのリストを返すメソッドが必要です。

たとえば、私は次のようなことをしたいと思います。

ServerModel *status = [[MyApiClient sharedClient] getServerStatus];

次に、ApiClientは内部でWebサービスを呼び出し、XMLを解析して、モデルを返します。どうやってやるの?通常、XMLが解析されると呼び出されるデリゲートを使用しますが、ApiClientのシングルトンの性質により、複数のデリゲートが存在する可能性がありますか?

誰かがこれに光を当てることができることを願っています、ありがとう!

4

2 に答える 2

4

デリゲートの代わりにブロックを使用します。

私の ApiClient クラスから:

- (void)getPath:(NSString *)path 
     parameters:(NSDictionary *)parameters 
        success:(void (^)(id response))success 
        failure:(void (^)(NSError *error))failure 
{   
    NSURLRequest *request = [self requestWithMethod:@"GET" path:path parameters:parameters];
    [self enqueueHTTPOperationWithRequest:request success:success failure:failure];
}

-(void)fetchAllUsersSuccess:(void (^)(id))success 
                     failure:(void (^)(NSError *))failure
{
    [self getPath:@"/api/mobile/user/" 
       parameters:nil 
          success:^(id response) {  

                      if([response isKindOfClass:[NSXMLParser class]]){
                          //parse here to new dict
                          success(newDict);
                      } else
                          success(response);

          } failure:^(NSError *error) {
              failure(error);
          }];
}

これで、次のように使用できます。

ServiceApiClient *apiClient = [ServiceApiClient sharedClient];

[apiClient fetchAllUsersSuccess:^(id dict) {
    for (NSDictionary *object in [dict objectForKey:@"objects"]) {
        [ServiceUser addUserFromDictionary:object
                                 inContext:self.managedObjectContext];
    }
    NSError *error= nil;
    [self.managedObjectContext save:&error];
    if (error) {
        NSLog(@"%@", error);
    }
} failure:^(NSError * error) {
    NSLog(@"%@", error);
}];
于 2011-11-30T10:59:43.163 に答える
0

(この「一種の」回答については事前にお詫び申し上げますが、より良い解決策に向けて取り組んでいます...)

一歩下がって、デザインについて慎重に考える必要があります。

設計の何かがシングルトンである必要があるという考えがあるため、問題が発生していますが、次のいずれかです。

1)それは実際には必要ありません。

2)その仕事をする何かがすでに存在しているかもしれません (例えば、あなたが使っている HTTP ライブラリ)。

また

3)間違ったことをシングルトンにしている、またはシングルトンのアイデアでうまく機能するように設計を適切な部分に分割していない

では、シングルトン アプローチを採用する理由を明確に教えていただけますか? 一度に 1 つのネットワーク リクエストのみが発生するようにするだけですか? シングルトン オブジェクトにステートフルの概念はありますか? 次に、この回答やコメントなどを更新します。

(余談:場合によっては、' strong ' シングルトンが本当に必要になる可能性があることも付け加えておきます。これは、可能なインスタンスが実際に 1 つしかなく、そのメカニズムがオブジェクトに組み込まれていることを意味します。やっている - しかし、これはそうではありません.代替手段は「弱い」シングルトンです.これは、実際に作業を行うコアオブジェクトが単純なオブジェクトを持っていることを意味します.init通常のメソッドですが、共通オブジェクトへの共有アクセスは、共有インスタンスをインスタンス化/保持する一種の単純な「ファクトリ」である別のオブジェクトを介して行われます。この弱いシングルトンのアイデアの利点は、コードがさまざまなコンテキストでより再利用可能になることです。たとえば、後で複数の HTTP リクエスト/セッションを同時に実行することを決定できます。また、テストを書く際の問題が軽減されることもあります)。

于 2011-11-30T11:01:59.660 に答える