SwiftのURLSession

(2020-05-31)

SwiftのURLSessionは ネットワーク通信を行うURLSessionTaskを生成するオブジェクト。

func request(_ session: URLSession) -> () -> Void { return
    {
        guard let url = URL(string: "https://api.publicapis.org/health") else { return }
        var request = URLRequest(url: url)
        request.httpMethod = "GET"
        request.addValue("application/json", forHTTPHeaderField: "content-type")

        let task = session.dataTask(with: request) { data, response, error in
            guard let httpResponse = response as? HTTPURLResponse else {
                print("not http response \(error)")
                return
            }
            guard httpResponse.statusCode / 100 == 2 else {
                print("bad status code: \(httpResponse.statusCode)")
                return
            }
            if let data = data {
                if let str = String(data: data, encoding: .utf8) {
                    print(str) // => {"alive": true}
                }
            }
        }
        task.resume()
    }
}

シングルトンのsharedのほか、コンストラクタに URLSessionConfiguration を渡して、allowsCellularAccess といった設定やdelegateを持ったインスタンスを作ることもできる。

  • default: 挙動はsharedと同じ
  • ephemeral: キャッシュ、cookie、認証情報をディスクに書き込まない
  • background: アプリがフォアグラウンドになくても裏で通信し続ける。通信が終わったときにアプリが終了していたらバックグラウンドで再起動しUIApplicationDelegateのメソッドでidentifierが通知される。キューが全て捌けたときURLSessionDelegateのurlSessionDidFinishEvents()が呼ばれる。
struct ContentView: View {
    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            Button("default", action: request(URLSession(configuration: .default)))
            Button("ephemeral", action: request(URLSession(configuration: .ephemeral)))
            // Button("background", action: request(URLSession(configuration: .background(withIdentifier: "foo"))))
            // => Completion handler blocks are not supported in background sessions. Use a delegate instead
        }
    }
    ...
}

delegateを強参照で持つためsessionを明示的に無効化しないとメモリリークする

let session = URLSession(configuration: .default, delegate: self, delegateQueue: nil)
session.invalidateAndCancel()
// or session.finishTasksAndInvalidate()