Alamofireを読んだ

2014-08-14#swift

Alamofireとは

使い方

Alamofire.request(.GET, "http://httpbin.org/get")
         .responseJSON { (request, response, JSON, error) in
                           println(JSON)
                       }

Alamofire.request(.GET, "http://httpbin.org/get", parameters: ["foo": "bar"])
         .authenticate(HTTPBasic: user, password: password)
         .responseJSON { (request, response, JSON, error) in
                           println(JSON)
                       }
         .responseString { (request, response, string, error) in
                             println(string)
                         }

※読んだコードのコミット番号は76266c95564912f228e76a1868e50b6a33f104e7である。

Alamofire.swift

tl;dr

L:25

public struct Alamofire {
    // ...
}

L:928

最初に呼ばれるメソッドであるAlamofire.requestの実装を読む。

extension Alamofire {
    // ...

    static func request(method: Method, _ URL: String, parameters: [String: AnyObject]? = nil, encoding: ParameterEncoding = .URL) -> Request {
        return Manager.sharedInstance.request(encoding.encode(URLRequest(method, URL), parameters: parameters).0)
    }
}

L:141

Managerクラスの初期化について見る。

class Manager {
    class var sharedInstance: Manager {
        struct Singleton {
            static let instance = Manager()
        }

        return Singleton.instance
    }
}

L:208

func request(request: NSURLRequest) -> Request {
    // ...

    var dataTask: NSURLSessionDataTask?
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
        dataTask = self.session.dataTaskWithRequest(mutableRequest)
    }

    let request = Request(session: self.session, task: dataTask!)
    self.delegate[request.delegate.task] = request.delegate
    request.resume()

    return request
}

L:403

class Request {
    // ...

    private init(session: NSURLSession, task: NSURLSessionTask) {
        self.session = session

        if task is NSURLSessionUploadTask {
            self.delegate = UploadTaskDelegate(task: task)
        } else if task is NSURLSessionDownloadTask {
            self.delegate = DownloadTaskDelegate(task: task)
        } else if task is NSURLSessionDataTask {
            self.delegate = DataTaskDelegate(task: task)
        } else {
            self.delegate = TaskDelegate(task: task)
        }
    }

    // ...

    func resume() {
        self.task.resume()
    }
}

L:208

Requestオブジェクトの概要をつかんだので、requestメソッドに戻る。

func request(request: NSURLRequest) -> Request {
    // ...

    let request = Request(session: self.session, task: dataTask!)
    self.delegate[request.delegate.task] = request.delegate
    request.resume()

    return request
}

L:229

class SessionDelegate: NSObject, NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate {
    private var subdelegates: [Int: Request.TaskDelegate]
    private subscript(task: NSURLSessionTask) -> Request.TaskDelegate? {
        get {
            return self.subdelegates[task.taskIdentifier]
        }

        set(newValue) {
            self.subdelegates[task.taskIdentifier] = newValue
        }
    }

    // ...

    required override init() {
        self.subdelegates = Dictionary()
        super.init()
    }
}

requestメソッドの実装についておおまかに読んだので、続いてresponseメソッドを読んでいく。responseメソッドはrequestメソッドの返り値であるRequest型に対して呼ばれているので、Requestクラスの定義を調べる。

L:458

func response(completionHandler: (NSURLRequest, NSHTTPURLResponse?, AnyObject?, NSError?) -> Void) -> Self {
    return response({ (request, response, data, error) in
                        return (data, error)
                    }, completionHandler: completionHandler)
}

func response(priority: Int = DISPATCH_QUEUE_PRIORITY_DEFAULT, queue: dispatch_queue_t? = nil, serializer: (NSURLRequest, NSHTTPURLResponse?, NSData?, NSError?) -> (AnyObject?, NSError?), completionHandler: (NSURLRequest, NSHTTPURLResponse?, AnyObject?, NSError?) -> Void) -> Self {

    dispatch_async(self.delegate.queue, {
        dispatch_async(dispatch_get_global_queue(priority, 0), {
            let (responseObject: AnyObject?, error: NSError?) = serializer(self.request, self.response, self.delegate.data, self.delegate.error)

            dispatch_async(queue ?? dispatch_get_main_queue(), {
                completionHandler(self.request, self.response, responseObject, error)
            })
        })
    })

    return self
}

L:497

private class TaskDelegate: NSObject, NSURLSessionTaskDelegate {
    // ...

    let queue: dispatch_queue_t?

    // ...

    init(task: NSURLSessionTask) {
        // ...

        let label: String = "com.alamofire.task-\(task.taskIdentifier)"
        let queue = dispatch_queue_create((label as NSString).UTF8String, DISPATCH_QUEUE_SERIAL)
        dispatch_suspend(queue)
        self.queue = queue
    }
}

self.delegate.queueがどのようなキューなのか把握したのでresponseメソッドに戻る。

L:464

func response(priority: Int = DISPATCH_QUEUE_PRIORITY_DEFAULT, queue: dispatch_queue_t? = nil, serializer: (NSURLRequest, NSHTTPURLResponse?, NSData?, NSError?) -> (AnyObject?, NSError?), completionHandler: (NSURLRequest, NSHTTPURLResponse?, AnyObject?, NSError?) -> Void) -> Self {

    dispatch_async(self.delegate.queue, {
        dispatch_async(dispatch_get_global_queue(priority, 0), {
            let (responseObject: AnyObject?, error: NSError?) = serializer(self.request, self.response, self.delegate.data, self.delegate.error)

            dispatch_async(queue ?? dispatch_get_main_queue(), {
                completionHandler(self.request, self.response, responseObject, error)
            })
        })
    })

    return self
}

次に、通信が完了したあとdelegateがどのように呼ばれていくか調べる。まず、delegateオブジェクトは何か調べるため、NSURLSessionオブジェクトが初期化されている部分を読む。

L:197

class Manager {
    // ...

    required init(configuration: NSURLSessionConfiguration! = nil) {
        self.delegate = SessionDelegate()
        self.session = NSURLSession(configuration: configuration, delegate: self.delegate, delegateQueue: self.operationQueue)
    }
}

L:229

class SessionDelegate: NSObject, NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate {
    // ...
}

NSURLSessionDataDelegateのメソッドの実装を見てみる。

L:336

func URLSession(session: NSURLSession!, dataTask: NSURLSessionDataTask!, didReceiveData data:NSData!) {
    if let delegate = self[dataTask] as? Request.DataTaskDelegate {
        delegate.URLSession(session, dataTask: dataTask, didReceiveData: data)
    }

    self.dataTaskDidReceiveData?(session, dataTask, data)
}

というわけで、実際にdelegateメソッドを実行しているクラスを読む。

L:598

func URLSession(session: NSURLSession!, dataTask: NSURLSessionDataTask!, didReceiveData data: NSData!) {
    self.dataTaskDidReceiveData?(session, dataTask)

    self.mutableData.appendData(data)
}

NSURLSessionオブジェクトによる通信が完了したときに呼ばれるdelegateメソッドはNSURLSessionTaskDelegateプロトコルのURLSession(_:task:didCompleteWithError:)というメソッドなので、これの実装を読む。

L:558

func URLSession(session: NSURLSession!, task: NSURLSessionTask!, didCompleteWithError error: NSError!) {
    self.error = error
    dispatch_resume(self.queue)
}