読者です 読者をやめる 読者になる 読者になる

assaulter's diary

最近はバイクブログと化している...

AmazonS3とiOS間でファイルをやりとりする(その2)

Objective-C AWS

前回 - AmazonS3とiOS間でファイルをやりとりする(その1) - assaulter's diary
の続きになります。僕はこういう感じで実装しました。

ダウンロード

仕様 : ユーザーにはDLの結果のみを見せる(今回はStringを返す)。データはよしなに扱う。

Clientを作成

メンバで保持。初期化時に鍵が必要。また、リージョンを設定しておく(やらない場合はデフォルトが入ったはず)。

- (id)init {
    if (self = [super init]) {
        _client = [[AmazonS3Client alloc] initWithAccessKey:ACCESS_KEY_ID withSecretKey:SECRET_KEY];
        _client.endpoint = [AmazonEndpoints s3Endpoint:AP_NORTHEAST_1];
    }
    return self;
}
ダウンロードapi
/// 公開する関数
- (void)downloadDataWithCompletion:(void(^)(NSString* message))resultBlock {
    [self getDataWithCompletion:^(S3GetObjectResponse *response) {
        /// response.bodyに格納されているので、よしなにやる
        if (response.bodyを使ってよしなにやった結果) {
            resultBlock(@"DL成功");
        } else {
            resultBlock(NSLocalizedString(@"保存失敗");
        }
    } errorBlock:^(NSError *error) {
        resultBlock(error.userInfo[@"NSLocalizedDescription"]);
    }];
}

/// ヘルパ関数
- (void)getDataWithCompletion:(void(^)(S3GetObjectResponse* response))responseBlock errorBlock:(void(^)(NSError* error))errorBlock {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        S3GetObjectRequest* getRequest = [[S3GetObjectRequest alloc] initWithKey:@"オブジェクトの名前" withBucket:@"バケット名"];
        getRequest.contentType = CONTENT_TYPE;
        
        S3GetObjectResponse* getResponse = [self.client getObject:getRequest];
        /// ここからmain threadで処理される(非同期)
        dispatch_async(dispatch_get_main_queue(), ^{
            if (getResponse.error) {
                errorBlock(getResponse.error);
            } else {
                responseBlock(getResponse);
            }
        });
    });
}

通信してレスポンスを取ってくるところの非同期処理はGCDを使いました。
参考 - 8.2 Grand Central Dispatch · mixi-inc/iOSTraining Wiki · GitHub
ネストはちょい深くなるけど、mainスレッドに非同期で返す部分をわざわざperformSelectorOnMainThreadでやると関数書かないといけないので、block返すだけとかそういう場合はこっちの方がスッキリするかな。

アップロード

あんま変わりませんね。clientは既に用意されている前提で、ユーザーには結果しか返しません。

/// 公開する関数
- (void)uploadDataWithCompletion:(void(^)(NSString* message))resultBlock {
    [self putDataWithResponseBlock:^(S3PutObjectResponse *response) {
        resultBlock(@"uploadに成功した");
    } errorBlock:^(NSError *error) {
        resultBlock(error.userInfo[@"NSLocalizedDescription"]);
    }];
}

/// ヘルパー
- (void)putDataWithResponseBlock:(void(^)(S3PutObjectResponse* response))responseBlock errorBlock:(void(^)(NSError* error))errorBlock {
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        S3PutObjectRequest* putRequest = [[S3PutObjectRequest alloc] initWithKey:@"オブジェクト名" inBucket:@"バケット名"];
        putRequest.contentType = CONTENT_TYPE;
        putRequest.data = 適当なメソッドでデータを取ってくる;
        
        S3PutObjectResponse* putResponse = [self.client putObject:putRequest];
        dispatch_async(dispatch_get_main_queue(), ^{
            // ここからはmainThreadで実行される
            if (putResponse.error) {
                errorBlock(putResponse.error);
            } else {
                responseBlock(putResponse);
            }
        });
    });
}