[iOS 11]NSURLSessionの新しいプロパティ(waitsForConnectivity)で接続監視が可能になりました #WWDC17
1 はじめに
iOS 11では、NSURLSessionに、接続状態を監視する機能が組み込まれました。
これまでは、NSURLSessionでアクセスを開始した時、ネットワークに問題があると、直ちにエラーとなっていました。 そして、ネットワークの問題が解消された後に、アクセスを再開する場合、改めてセッションを開始する必要がありました。
また、「接続が確保されたら、直ちにアクセスしたい」と言うような要件では、SCNetworkReachabilityなどを使用したポーリングの実装が必要でした。
iOS 11以降では、このような接続監視の実装が、まったく必要なくなったと言えます。
本記事は Apple からベータ版として公開されているドキュメントを情報源としています。 そのため、正式版と異なる情報になる可能性があります。ご留意の上、お読みください。
2 動作確認
次のようなサンプルで動作を確認してみます。
requestCachePolicyは、.reloadIgnoringLocalCacheDataに設定し、動作が確認しやすいように、キャッシュを無効にしました。
class ViewController: UIViewController { // ・・・略・・・ @IBAction func tapConnectButton(_ sender: Any) { let config = URLSessionConfiguration.default config.requestCachePolicy = .reloadIgnoringLocalCacheData // キャッシュ無効にする config.waitsForConnectivity = false // デフォルト値 let session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main) let url = URL(string:"https://classmethod.jp/")! let task = session.dataTask(with: url) { (data, response, error) in if let error = error { print("ERROR \(error)") print(error) } else { print("SUCCESS statusCode : \((response as! HTTPURLResponse).statusCode)") } } task.resume() } } extension ViewController: URLSessionTaskDelegate { func urlSession(_ session: URLSession, taskIsWaitingForConnectivity task: URLSessionTask) { print("URLSession:taskIsWaitingForConnectivity:") } }
(1) 従来の動作
当初、新しく追加されたプロパティであるwaitsForConnectivityを、false(デフォルト値)に設定し、今までと同じで動作を見ておきます。
インターネットにアクセスを開始すると、接続状態に問題がない場合、error = nil でdataTask の completionHandler:ハンドラに制御が移ります。
Log> SUCCESS statusCode : 200
そして、接続状態に問題がある状況を作為するため、機内モードをONにして、実行してみると、error != nil で、やはり直ちにcompletionHandler:ハンドラに制御は返ります。
Log> ERROR Error Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline."
(2) 接続状態の監視
続いて、waitsForConnectivityを、trueに設定し、同様に動作を確認してみます。
接続状態に問題がない場合、error = nil でdataTask の completionHandler:ハンドラに制御が戻ります。これは、上の動作と同じです。
Log> SUCCESS statusCode : 200
そして、機内モードをONにして、実行してみると、completionHandler:ハンドラへは帰らず、dataTaskがブロックしたようになります。
そして、この時、これも新設されたデリゲートメソッドである、urlSession(_:taskIsWaitingForConnectivity:)が呼ばれます。
Log> URLSession:taskIsWaitingForConnectivity:
続いて、このブロックされた状態のままで、機内モードをOFF(インターネット接続を復活)にすると、error = nil でdataTask の completionHandler:ハンドラに制御が戻ります。
SUCCESS statusCode : 200
3 接続不良な状態
先の動作確認では、機内モードをONにすることで、接続不良の状態を試しましたが、WWDC2017のセッションの中では、この他に、Wi-Fiネットワークが繋がっていないときや、電波な受信できないときなどが、列挙されていました。
色々な要因でインタネット接続が確保できない時、この監視が有効になるようです。
WWDC2017 Advances in Networking より
4 waitsForConnectivity
このように、waitsForConnectivityをtrueに設定するだけで、URLSessionはネットワークの状態を監視し、タスクの開始を待機するようになります。
なお、バックグラウンドで動作するURLSessionでは、自動的に有効になっているとのことです。
5 URLSession:taskIsWaitingForConnectivity:
URLSessionTaskDelegateに新しく追加された、URLSession:taskIsWaitingForConnectivity:は、接続監視の待機に入った時、1回だけ呼ばれます。(待機に入らなかった場合は、呼ばれません)
URLSessionTaskDelegate urlSession(_:taskIsWaitingForConnectivity:)
6 最後に
waitsForConnectivityを使用することで、ポーリングの実装や、重複したNSURLSessionの接続を記述する必要はなくなると思います。
ただし、これを利用する場合、URLSessionTaskDelegateを適切に処理することは、新しくアプリ開発者の仕事であると言えそうです。
7 参考リンク
Advances in Networking, Part 2
NSURLSession
NSURLSessionTaskDelegate
urlSession(_:taskIsWaitingForConnectivity:)
taskIsWaitingForConnectivity: