Twitter.frameworkでアップロードプログレスを取得する
前回と同じようなネタですが、
Twitter.frameworkを使ってイメージをポストする際に、公式のサンプルに従うとアップロードの進捗を知ることができないので、それをできるようにしようという話です。
公式のドキュメントには、
- (void)performTWRequestUpload { NSURL *url = [NSURL URLWithString: @"https://upload.twitter.com/1/statuses/update_with_media.json"]; TWRequest *request = [[TWRequest alloc] initWithURL:url parameters:nil requestMethod:TWRequestMethodPOST]; [request setAccount:[self.accounts objectAtIndex:0]]; UIImage *image = [UIImage imageNamed:@"larry.png"]; NSData *imageData = UIImagePNGRepresentation(image); [request addMultiPartData:imageData withName:@"media[]" type:@"multipart/form-data"]; NSString *status = @"just setting up my twttr #iOS5"; [request addMultiPartData:[status dataUsingEncoding:NSUTF8StringEncoding] withName:@"status" type:@"multipart/form-data"]; [request performRequestWithHandler: ^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) { NSDictionary *dict = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:responseData options:0 error:nil]; dispatch_async(dispatch_get_main_queue(), ^{ }); }]; }
という、短いコードが載っています(コメントは削除しました)がこれだとperformRequestWithHandlerがレスポンスを取得したときに、ブロックに入るので進捗が分かりません。
で、
には、
Alternatively, you can use the signedURLRequest method to create a request that you send using an NSURLConnection object.
と書いてあって、signedURLRequestをつかってリクエストするといいよとちょろっと書いてあります。このプロパティ、ググってみれば分かるのですが殆ど全く情報がありません。
performRequestWithHandlerの直前でsignedURLRequestの内容をみてもらえれば分かるのですが、TWRequestを使って作成された発行される前のNSURLRequestが入っています。なので、これを直接使えばNSURLConnectionをつかってリクエストできます。つまり、
NSURLConnection *connection =
[[NSURLConnection alloc] initWithRequest:request.signedURLRequest delegate:self];
とすれば、performRequestWithHandlerと同じ動作をします。公式サイトの例ならばイメージがポストされます。当然、NSURLConnectionDelegateやNSURLConnectionDataDelegateを実装して、その後の処理することができます。
ただし、不勉強なので原因は分かりませんが、ブロックの中で上記コードを動かすとDelegateメソッドが呼ばれません(多分スレッドが違うから)。なので、dispatch_asyncで呼び出すかperformSelectorOnMainThreadを使って呼び出す必要があります。私の実装では
Delegateを実装するクラスでNSURLDataDelegateを実装(delegateはimplementsなのか知らん?)
@interface TwitterPhotoSubmitter : PhotoSubmitter<PhotoSubmitterProtocol, NSURLConnectionDataDelegate, NSURLConnectionDelegate, UIAlertViewDelegate> @end
実装は次のように
- (void)startConnectionWithRequest:(NSURLRequest *)request{ NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self]; }
NSURLConnectionを生成するメソッドを用意し,
[self performSelectorOnMainThread:@selector(startConnectionWithRequest:) withObject: request.signedURLRequest waitUntilDone:NO];
として、ブロックの中でTWRequestを作り終わったあたりで呼び出します。
最後に、NSURLConnectionDataDelegateのメソッドを
- (void)connection:(NSURLConnection *)connection didSendBodyData:(NSInteger)bytesWritten totalBytesWritten:(NSInteger)totalBytesWritten totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite{ NSLog(@"%f", (float)totalBytesWritten / (float)totalBytesExpectedToWrite); }
とか実装すればいいです。
APIの仕様、それぞれに採用している方法が違って、複数のサービスを使うと思うとまじで面倒くさい...