web-dev-qa-db-ja.com

AFNetworkingでJSON応答を解析する

Objective-CでAFNetworkingを使用してJSON投稿を設定し、次のコードでサーバーにデータを送信しています。

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
NSDictionary *parameters = @{@"name": deviceName, @"model": modelName, @"pin": pin};
manager.requestSerializer = [AFJSONRequestSerializer serializer];
[manager.requestSerializer setValue:@"Content-Type" forHTTPHeaderField:@"application/json"];
[manager POST:@"SENSORED_OUT_URL" parameters:parameters

success:^(AFHTTPRequestOperation *operation, id responseObject)
{
    NSLog(@"JSON: %@", responseObject);
}

failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
    NSLog(@"Error: %@", error);
}];

同じリクエストで情報を受信して​​いますが、データをNSStringに送信します。 AFNetworkingでそれを行うにはどうすればよいですか?

12
James

responseObjectはNSArrayまたはNSDictionaryです。実行時にisKindOfClass:を使用して確認できます。

if ([responseObject isKindOfClass:[NSArray class]]) {
    NSArray *responseArray = responseObject;
    /* do something with responseArray */
} else if ([responseObject isKindOfClass:[NSDictionary class]]) {
    NSDictionary *responseDict = responseObject;
    /* do something with responseDict */
}

JSONの文字列が本当に必要な場合は、operation.responseStringを調べることで利用できます。

28
Aaron Brager

この場合、WebサービスがJSONで応答すると、AFNetworkingがシリアル化を行い、responseObjectはおそらくNSArrayまたはNSDictionaryオブジェクト。

このようなオブジェクトは、JSONコンテンツを含む文字列よりも便利です。

8
RaffAl

私の場合、それは(多分それは助けることができる)のように見えます

AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];

manager.requestSerializer = [AFJSONRequestSerializer serializer];
[manager POST:url parameters:params
      success:^(AFHTTPRequestOperation *operation, id responseObject) {
          NSDictionary *jsonDict = (NSDictionary *) responseObject;
          //!!! here is answer (parsed from mapped JSON: {"result":"STRING"}) ->
          NSString *res = [NSString stringWithFormat:@"%@", [jsonDict objectForKey:@"result"]];
      } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
          //....
      }
 ];

また、応答オブジェクトのタイプをチェックするのも素晴らしいでしょう(例 https://stackoverflow.com/a/21962445/3628317 answer)

5
levo4ka

私は次のようにAFHTTPClientをサブクラス化するのが最も効果的だと思います:

//  MyHTTPClient.h

#import <AFNetworking/AFHTTPClient.h>

@interface MyHTTPClient : AFHTTPClient

+ (instancetype)sharedClient;

@end

//  MyHTTPClient.m

#import "MyHTTPClient.h"

#import <AFNetworking/AFJSONRequestOperation.h>

static NSString *kBaseUrl = @"http://api.blah.com/yada/v1/";

@implementation MyHTTPClient

+ (instancetype)sharedClient {
    static id instance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[self alloc] init];
    });
    return instance;
}

- (id)init {
    if (self = [super initWithBaseURL:[NSURL URLWithString:kBaseUrl]]) {
        self.parameterEncoding = AFJSONParameterEncoding;

        [self setDefaultHeader:@"Accept" value:@"application/json"]; // So AFJSONRequestOperation becomes eligible for requests.
        [self registerHTTPOperationClass:[AFJSONRequestOperation class]]; // So that it gets used for postPath etc.
    }
    return self;
}

@end

重要なビットは次のとおりです。

  • AFJSONRequestOperationが適格になるような方法で「Accept」を設定します。
  • AFJSONRequestOperationをhttp操作クラスに追加します。

その後、次のように使用できます。

#import "MyHTTPClient.h"

@implementation UserService

+ (void)createUserWithEmail:(NSString *)email completion:(CreateUserCompletion)completion {
    NSDictionary *params = @{@"email": email};
    [[MyHTTPClient sharedClient] postPath:@"user" parameters:params success:^(AFHTTPRequestOperation *operation, NSDictionary *responseObject) {
        completion([responseObject[@"userId"] intValue], YES);
    } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
        completion(0, NO);
    }];
}

@end

この美しさは、responseObjectが自動的にJSON解析されて辞書(または配列)になることです。非常にきれいな。

(これはafnetworking 1.x用です)

1
Chris