iOS7からNSURLSessionという新しいクラスが追加された。
通信周りの処理がNSURLConnectionより充実簡単になったのと、バックグラウンド処理が使えるようになったらしい。
ということで、試しに使ってみたらつまらないところでハマったのでメモ。
completionHandlerの中でUITableView:reloadを走らせようとしたら挙動がおかしくなった。
cellForRowAtIndexPathがすぐに呼ばれず、テーブルビューがスクロールされるタイミングで呼ばれる。
NSURLSession *session = [NSURLSession sharedSession];
NSURL *url = [NSURL URLWithString:@"http://hogefuga.com"];
[[session dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
[_tableView reloadData];
}] resume];
原因は、completionHandlerがmain threadで実行されてなかったからでした。
UIに変更を加える処理はmain threadで実行する必要があります。
blockの中にブレークポイントしかけると
SerialQueueですね。
取り急ぎ、dispatch_get_main_queueで囲ってやればmain threadで実行されるようになる。
NSURLSession *session = [NSURLSession sharedSession];
NSURL *url = [NSURL URLWithString:@"http://hogefuga.com"];
[[session dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
[_tableView reloadData];
});
}] resume];
そういえば、NSURLConnectionはどうだったっけ?と思い振り返ると
NSURL *URL = [NSURL URLWithString:@"http://hogefuga.com"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
[_tableView reloadData];
}];
[NSOperationQueue mainQueue]で指定していました。
では、NSURLSessionでも指定できるのでは無いかと思い、調べたらありました。
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSURL *url = [NSURL URLWithString:@"http://hogefuga.com"];
[[session dataTaskWithURL:url
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
[_tableView reloadData];
}] resume];
sharedSessionはデフォルトの設定が適用されるらしいです。
仕組みを理解してから使うべきでした。
反省しました。