NSURLConnectionがiOS 9.0でDeprecatedになってから時間も経ち、もうiOS 12が出る時勢にNSURLSessionへの書き換え事案が発生した。
感想
NSURLConnectionDataDelegateとNSURLSessionDataDelegateの互換性はわりと確保されていて助かった。 なぜかcompletionHandlerにわたす引数の順序が変わってたけど。
NSURLConnectionにおけるdidFinishLoadingとdidFailWithErrorが、 didCompleteWithErrorにまとまったので、errorをちゃんと確認しないといけないのが「あーそうですかぁ」という感じ。
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { if (error) { // connection:didFailWithError: 相当の処理 return; } // connectionDidFinishLoading: 相当の処理 }
だいたいどんなことをしたか。
サブスレッドでNSURLConnectionを動かすために、NSRunLoop
とwhileを組み合わせて待機させていた。
また、そのサブスレッドの中で同期的な動きをするところに依存していた。
これをNSURLSessionに書き換えるとき、RunLoopを使う必要がないので、NSConditionでwaitをかけて再現した。
// before - (void) download:(NSURLRequest *)request { // befor self.connection = [NSURLConnection connectionWithRequest:request delegate:self]; while(!self.completed && [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]) ; } - (void)connectionDidFinishLoading:(NSURLConnection *)connection { self.completed = YES; } - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { self.completed = YES; }
// after - (void) download:(NSURLRequest *)request { NSURLSessionConfiguration *configuration = NSURLSessionConfiguration.ephemeralSessionConfiguration; self.session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil]; self.task = [self.session dataTaskWithRequest:request]; [self.task resume]; [self.condition lock]; [self.condition wait]; [self.condiiton unlock]; self.condition = nil; } - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { [self.condition lock]; [self.condition signal]; [self.condition unlock]; }
delegateQueue
にnil
を与えているのはどこでもいいから他のスレッドで処理してもらうため。
後続処理のwait
によってsessionを作るスレッドはスリープしてしまう。