Skip to content

Instantly share code, notes, and snippets.

@shinyaohira
Last active June 29, 2020 18:32
Show Gist options
  • Save shinyaohira/6239991 to your computer and use it in GitHub Desktop.
Save shinyaohira/6239991 to your computer and use it in GitHub Desktop.
AFNetworking

ネットワークを扱うフレームワークを新規に作る必要はない。 このフレームワークは非常に多くのアプリで検証されており、必要な機能のほとんどを含んでいる。

ターゲットOSとAFNetworkingの対応

  • iOS 7+の場合、AFNetworking 2.xの最新版を使う
  • iOS 5-6の場合、AFNetworking 1.xの最新版を使う
  • iOS 4.3の場合、AFNetworking 0.10.xの最新版を使う

ビルド時の注意

Build Phases -> Link Binary With Librariesに以下のライブラリを追加する。

  • Security.framework
  • MobileCoreServices.framework
  • SystemConfiguration.framework

Prefix.pchに以下のインポート文を追加する。

#ifdef __OBJC__
  #import <UIKit/UIKit.h>
  #import <Foundation/Foundation.h>
+  #import <SystemConfiguration/SystemConfiguration.h>
+  #import <MobileCoreServices/MobileCoreServices.h>
 #endif

AFHTTPClient

主な機能

  • ベースURLを設定することができ、リクエストは相対パスで行うことができる
  • パラメータはDictionaryで指定することができる
  • リクエストに共通で付加するデフォルトヘッダを設定することができる
    • 認証、Content-Type、Acceptなど
  • レスポンスの形式に応じてパースを自動的に行うことができる
    • レスポンスをJSONオブジェクトとして取得するなど
  • 接続先のネットワーク到達性を確認することができる

ガイドライン

  • APIのエンドポイントごとに、対応するクラスをAFHTTPClientをサブクラスとして作成する
  • シングルトンのインスタンスを返すクラスメソッドを作成する
    • 同じ設定を何度も行わなくても良いようにするため
  • ファイルをアップロードする場合は、-multipartFormRequestWithMethod:path:parameters:constructingBodyWithBlock:メソッドを使用する
  • リクエストパラメータをJSONで送りたい場合は、parameterEncodingプロパティにAFJSONParameterEncodingを設定する
  • AFHTTPClientのオペレーションキューにリクエストを入れる前に、リクエストオペレーションの設定をしたり、後で使うためにリクエストオペレーションを保持しておきたい場合は、-HTTPRequestOperationWithRequest:success:failureを使う
    • URLリクエストオブジェクトで行いたい場合は、-requestWithMethod:path:parametersを使う
@interface SampleAPIClient : AFHTTPClient

+ (instancetype)sharedClient;

- (instancetype)initWithBaseURL:(NSURL *)url;

- (void)getSampleDataWithPath:(NSString *)relativePath
    parameters:(NSDictionary *)parameters
    success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
    failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure;

@end
@implementation SampleAPIClient

+ (instancetype)sharedClient {
    static SampleAPIClient *_sharedClient;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        _sharedClient = [[SampleAPIClient alloc] initWithBaseURL:[NSURL URLWithString:kAPIBaseURL]];
    });
    return _sharedClient;
}

- (instancetype)initWithBaseURL:(NSURL *)url {
    self = [super initWithBaseURL:url];
    if (!self) return nil;

    // JSON形式のレスポンスを扱う
    [self registerHTTPOperationClass:AFJSONRequestOperation.class];
  
    // すべてのリクエストにJSONを受け付けるAcceptヘッダをつける
    [self setDefaultHeader:@"Accept" value:@"application/json"];
  
    // すべてのリクエストにUser-Agentヘッダをつける
    [self setDefaultHeader:@"User-Agent" value:@"sample"];

    return self;
}

- (void)getSampleDataWithPath:(NSString *)relativePath
                   parameters:(NSDictionary *)parameters
                      success:(void (^)(SampleModel *model))success
                      failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure {
    static NSDictionary * const defaultParameters = @{@"key1": @"value1", @"key2": @"value2"};
    NSMutableDictionary *composedParameters = [defaultParameters mutableCopy];
	[composedParameters addEntriesFromDictionary:parameters];

    // GETメソッドでJSONを取得する
    [self getPath:@"sample/data" parameters:composedParameters success:^(AFHTTPRequestOperation *operation, id responseObject) {
        success([SampleModel parseResponse:responseObject]);
    } failure:failure];
}

@end

接続先のネットワーク到達性を確認する

  • -networkReachabilityStatusプロパティで、接続先のネットワーク到達性を確認できる
  • -setReachabilityStatusChangeBlock:メソッドで、接続先のネットワーク到達性に変化があった場合に呼ばれるコールバックを設定することができる

UIImageViewのカテゴリ拡張

  • setImageWithURL:placeholderImage:で、URLで指定した画像を非同期で取得し、イメージを設定できる
    • 画像をキャッシュする機能がある
    • キャッシュが存在すればすぐにその画像を表示し、存在しなければplaceholderを表示してからURLで指定した画像を取得する
[imageView setImageWithURL:[NSURL URLWithString:@"http://example.com/image.png"] placeholderImage:[UIImage imageNamed:@"placeholder"]];

ファイルのダウンロード

NSURLRequest *request = [client requestWithMethod:@"GET" path:urlPath parameters:nil];
AFURLConnectionOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:filePath append:NO];

// ダウンロードのプログレスを表示する
[operation setDownloadProgressBlock:^(NSInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
    NSLog(@"progress: %f", (float)totalBytesRead / totalBytesExpectedToRead);
}];

// ダウンロードの成功、失敗を表示する
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
    NSLog(@"completed");
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
    NSLog(@"error: %@", error);
}];

// アプリが終了してもダウンロードを継続するよう設定する
[operation setShouldExecuteAsBackgroundTaskWithExpirationHandler:^{
     // ダウンロード中断時に行う処理を記述する
}];

[client enqueueHTTPRequestOperation:operation];

その他の設定

  • NSURLCacheを用いて、メモリとディスクのキャッシュサイズを指定する
  • ネットワーク通信時に、ステータスバーのネットワークアクセスインジケータを表示する
  • リクエストとレスポンスの内容をログに出力する
    • ボディも表示したい場合は、ログレベルをAFLoggerLevelDebug設定する
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // キャッシュサイズを設定
    NSURLCache *URLCache = [[NSURLCache alloc] initWithMemoryCapacity:4 * 1024 * 1024 diskCapacity:20 * 1024 * 1024 diskPath:nil];
    [NSURLCache setSharedURLCache:URLCache];

    // ネットワーク通信時にステータスバーのインジケータを表示
    [AFNetworkActivityIndicatorManager sharedManager].enabled = YES;

#ifdef DEBUG
    // リクエストとレスポンスの内容をログに出力
    [[AFHTTPRequestOperationLogger sharedLogger] startLogging];
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment