Swiftで同期HTTP通信を走らせる

 NSURLSession を使って通信を走らせる場合、コールバックやデリゲートなどで後処理を指定する非同期通信となります。基本的に通信処理を非同期で扱うのは正しいと思います。しかし、コールバックやデリゲート、FutureObservable などに縛られず処理を書きたいとなると、同期通信でないと困ります。

 そこで強制的に同期通信にしてしまうコードを書いてみました。これで晴れてコールバックを渡す必要も無く、デリゲートを指定する必要もない。そして FutureObservable に包む必要のない状態になりました。

public class HttpClientImpl {
    
    private let session: NSURLSession
    
    public init(config: NSURLSessionConfiguration? = nil) {
        self.session = config.map { NSURLSession(configuration: $0) } ?? NSURLSession.sharedSession()
    }
    
    public func execute(request: NSURLRequest) -> (NSData?, NSURLResponse?, NSError?) {
        var d: NSData? = nil
        var r: NSURLResponse? = nil
        var e: NSError? = nil
        let semaphore = dispatch_semaphore_create(0)
        session
            .dataTaskWithRequest(request) { (data, response, error) -> Void in
                d = data
                r = response
                e = error
                dispatch_semaphore_signal(semaphore)
            }
            .resume()
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
        return (d, r, e)
    }
    
}

 実際にUI層から呼び出す前に、適当なタイミングで Future なり Observable なりに lift すればよいので、同期である方が柔軟な設計が可能になるのではないかなと思います。execute の戻り型が、 Either<NSError, HttpResponse> とかになっているとさらに良さそうですね。

 純粋な HttpClientFutureObservable に依存する必然性がないので、このコードが安定したものであれば、使っていきたいと考えています。iOS開発に詳しい方、このコード実際どうなんですかね?(丸投げ)

One comment

  1. ピンバック: Swift4で同期通信をする - わがままに生きる

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です