その後のその後

iOSエンジニア 堤 修一のブログ github.com/shu223

API クライアントを AFNetworking を用いてつくる手順

ちょっとこの Web API 使ってなんかつくってみるか」ということがたまにある(とくにハッカソンで)ので、手早くつくれるように僕なりの手順をまとめてみました。


「共通処理の実装」までは簡単な文字列の置換で済むので、 ファイルテンプレートにしておく とより簡単になりそうです(参考:Xcodeのファイルテンプレートを自作する)。

0. クラスファイルを新規作成

AFHTTPClientのサブクラスとしてクラスファイルを新規作成する。

1. 共通処理の実装

APIキーをセットするメソッドの定義と実装と、オブジェクト初期化用のメソッド実装。

ヘッダファイル(.h)
+ (void)setAPIKey:(NSString *)APIKey;
実装ファイル(.m)
#import "AFJSONRequestOperation.h"
#define API_BASE_URL      @"http://xxxx"
@interface XXXX ()
@property (nonatomic) NSString *APIKey;
@end
+ (XXXX *)sharedClient
{
    static XXXX *sharedClient = nil;
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        sharedClient = [[XXXX alloc] initWithBaseURL:[NSURL URLWithString:API_BASE_URL]];
    });
    
    return sharedClient;
}

- (id)initWithBaseURL:(NSURL *)url
{
    if (self = [super initWithBaseURL:url]) {
        
        [self registerHTTPOperationClass:[AFJSONRequestOperation class]];
        [self setParameterEncoding:AFJSONParameterEncoding];
        [self setDefaultHeader:@"Accept"     value:@"application/json"];
    }
    
    return self;
}

+ (void)setAPIKey:(NSString *)APIKey {
    
    [[XXXX sharedClient] setAPIKey:APIKey];
}

2. 汎用Privateメソッドの実装

ここは各サービスの仕様に合わせて実装を変える必要がある。APIキーをセットする、とか、そのサービスにおけるAPIをたたく際の共通の処理をここで行う。


(APIキーをパラメータに渡す場合)

- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
                                      path:(NSString *)path
                                parameters:(NSDictionary *)parameters
{
    NSAssert(self.APIKey, @"API Key has not been set.\n\n");
    
    path = [path stringByAppendingFormat:@"?api_key=%@", self.APIKey];
    
    for (NSString *key in [parameters keyEnumerator]) {
        
        NSString *value = [NSString stringWithFormat:@"%@",
                           [parameters valueForKey:key]];
        
        NSAssert2([key length] && [value length],
                  @"invalid param! key:%@: value:%@", key, value);
        
        path = [path stringByAppendingFormat:@"&%@=%@", key, value];
    }

    NSMutableURLRequest *req = [super requestWithMethod:method
                                                   path:path
                                             parameters:nil];
        
    return req;
}

3. 各APIに対応したメソッドを書く

- (void)companyWithName:(NSString *)name
                handler:(void (^)(NSDictionary *result, NSError *error))handler
{
    NSAssert([name length], @"name is required");
    
    __weak XXXX *weakSelf = self;
    
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{

        NSString *path = [NSString stringWithFormat:@"company/%@.js", name];

        [weakSelf getPath:path
               parameters:nil
                  success:^(AFHTTPRequestOperation *operation, id responseObject) {
                      
                      dispatch_async(dispatch_get_main_queue(), ^{
                          
                          handler(responseObject, nil);
                      });
                      
                  } failure:^(AFHTTPRequestOperation *operation, NSError *error) {
                      
                      dispatch_async(dispatch_get_main_queue(), ^{
                          
                          handler(nil, error);
                      });
                  }];
    });
}

サンプル

この手順でつくったAPIクライアント