ブログなんかでよくある、画像と動画のアップロードをアプリ側から行う事案が発生したので、調べてみた。
まずは、アプリ側とサーバ側との通信は、こちらのライブラリを使用させてもらった。
シンプルで簡単に HTTP 通信が出来るライブラリを公開しました
Xcodeにインポートして、ライブラリ内の「Multipart POST」を使用する。
アプリというかiPhoneなりiPodなりで撮った写真をアップロードしたいので、以下のようなリクエストをサーバ側のファイルに対して投げる。
NSURL *URL = [NSURL URLWithString:@"http://.../hoge.php"]; R9HTTPRequest *request = [[R9HTTPRequest alloc] initWithURL:URL]; [request setHTTPMethod:@"POST"]; [request addBody:@"upload" forKey:@"query_type"]; [request setData:upData withFileName:strFileName andContentType:strContentsType forKey:strKey]; // リクエスト結果 [request setCompletionHandler:^(NSHTTPURLResponse *responseHeader, NSString *responseString){ //NSLog(@"%@", responseString); }]; // 画像アップロードの進捗状況を確認(1 = アップロード完了) [request setUploadProgressHandler:^(float newProgress){ NSLog(@"%g", newProgress); if (newProgress == 1) { NSLog(@"%@", "アップロードが完了しました!"); } }]; [request startRequest];
こんな感じ。setDataメソッドに対して画像が格納された、NSDataオブジェクトとアップロードしたい画像ファイルのContentTypeを指定するだけ。ラクチン!
今回はiOSデバイスで撮った画像と動画をアップロードしたかったので、ContentTypeはそれぞれ「image/png」と「video/quicktime」になります。
アップロードするには、サーバ側の設定なんかも必要です。Apacheの設定ですね。
めんどくさいので割愛します。
ここまでで単体ファイルのアップロードは実装できた。
実際のアプリでは、画像が最大3つ・動画が1つ同時にアップロード出来るの仕様(の予定)。
んで、それらのアップロードが全て完了したときにポップアップなりで知らせたかった。
普通にファイルを順序良くアップロードすると、完了前にポップアップが出ちゃう。
setUploadProgressHandlerでファイルのアップロードが完了した時に、次のファイルをアップロードするというネスト(笑)な作りにも出来たけど、これはあんまりだ…。
ってことで、「NSRunLoop」を使って一つのファイルがアップロードされるのを待って、次の処理を実行させるようにした。
(並列処理もできると思うけど、今回はこれで勘弁)
NSData *pngData = [[NSData alloc] initWithData:UIImagePNGRepresentation(img1)]; [self upData:pngData strFileName:@"photo1.png" strContentsType:@"image/png" strKey:@"upfile"]; //アラートでボタンを押すまで動作を中断する(待つ) alertFinished = NO; while (alertFinished == NO) { [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.5f]]; //0.5秒 }
コードはこんな感じ。アップロード処理を実行させたあとに、while文内でNSRunLoopを実行。
これで、alertFinishedフラグがONになるまでは次の処理をさせないように出来た。
alertFinishedをONにするタイミングはもちろん、アップロードが完了した時。
こんな感じでフラグをONにする。
// 画像アップロードの進捗状況を確認(1 = アップロード完了) [request setUploadProgressHandler:^(float newProgress){ NSLog(@"%g", newProgress); if (newProgress == 1) { NSLog(@"%@", "アップロードが完了しました!"); alertFinished = YES; } }];
あとは、この処理を繰り返せば一つ一つ順序良くアップロードができる、と思う。
まぁアップロードに失敗した時の例外処理なんかも必要だと思うので、一定時間待ったらループを抜ける処理とかも後から追加していきたいです。