swift – 与Alamofire的NSURLSession并发请求

前端之家收集整理的这篇文章主要介绍了swift – 与Alamofire的NSURLSession并发请求前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我的测试应用程序遇到了一些奇怪的行为。我有大约50个同时GET请求,我发送到同一个服务器。服务器是一个小型硬件上的嵌入式服务器,资源非常有限。为了优化每个单个请求的性能,我配置Alamofire.Manager的一个实例如下:
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration()
configuration.HTTPMaximumConnectionsPerHost = 2
configuration.timeoutIntervalForRequest = 30
let manager = Alamofire.Manager(configuration: configuration)

当我发送请求与manager.request(…),他们被调度成2对(如预期,与Charles HTTP代理检查)。奇怪的是,所有的请求,在第一个请求的30秒内没有完成,由于超时同时取消(即使他们还没有发送)。下面是一个展示行为的插图:

这是一个预期的行为,如何确保请求在它们甚至发送之前不会得到超时?

非常感谢!

是的,这是预期的行为。一个解决方案是在自定义的异步NSOperation子类中包装您的请求,然后使用操作队列的maxConcurrentOperationCount来控制并发请求数,而不是HTTPMaximumConnectionsPerHost参数。

原来的AFNetworking做了一个奇妙的工作包装在操作中的请求,这使得这个微不足道。但AFNetworking的NSURLSession实现从来没有这样做,Alamofire也没有。

您可以轻松地将请求包装在NSOperation子类中。例如:

class NetworkOperation : AsynchronousOperation {

    // define properties to hold everything that you'll supply when you instantiate
    // this object and will be used when the request finally starts
    //
    // in this example,I'll keep track of (a) URL; and (b) closure to call when request is done

    let URLString: String
    let networkOperationCompletionHandler: (_ responSEObject: Any?,_ error: Error?) -> ()

    // we'll also keep track of the resulting request operation in case we need to cancel it later

    weak var request: Alamofire.Request?

    // define init method that captures all of the properties to be used when issuing the request

    init(URLString: String,networkOperationCompletionHandler: @escaping (_ responSEObject: Any?,_ error: Error?) -> ()) {
        self.URLString = URLString
        self.networkOperationCompletionHandler = networkOperationCompletionHandler
        super.init()
    }


    // when the operation actually starts,this is the method that will be called

    override func main() {
        request = Alamofire.request(URLString,method: .get,parameters: ["foo" : "bar"])
            .responseJSON { response in
                // do whatever you want here; personally,I'll just all the completion handler that was passed to me in `init`

                self.networkOperationCompletionHandler(response.result.value,response.result.error)

                // now that I'm done,complete this operation

                self.completeOperation()
        }
    }

    // we'll also support canceling the request,in case we need it

    override func cancel() {
        request?.cancel()
        super.cancel()
    }
}

然后,当我想发起我的50个请求,我会做这样的事情:

let queue = OperationQueue()
queue.maxConcurrentOperationCount = 2

for i in 0 ..< 50 {
    let operation = NetworkOperation(URLString: "http://example.com/request.PHP?value=\(i)") { responSEObject,error in
        if responSEObject == nil {
            // handle error here

            print("Failed: \(error)")
        } else {
            // update UI to reflect the `responSEObject` finished successfully

            print("responSEObject=\(responSEObject!)")
        }
    }
    queue.addOperation(operation)
}

这样,这些请求将受maxConcurrentOperationCount的约束,我们不必担心任何请求超时。

这是一个示例AsynchronousOperation基类,它负责与异步/并发NSOperation子类关联的KVN:

//
//  AsynchronousOperation.swift
//
//  Created by Robert Ryan on 9/20/14.
//  Copyright (c) 2014 Robert Ryan. All rights reserved.
//

import Foundation

/// Asynchronous Operation base class
///
/// This class performs all of the necessary KVN of `isFinished` and
/// `isExecuting` for a concurrent `NSOperation` subclass. So,to developer
/// a concurrent NSOperation subclass,you instead subclass this class which:
///
/// - must override `main()` with the tasks that initiate the asynchronous task;
///
/// - must call `completeOperation()` function when the asynchronous task is done;
///
/// - optionally,periodically check `self.cancelled` status,performing any clean-up
///   necessary and then ensuring that `completeOperation()` is called; or
///   override `cancel` method,calling `super.cancel()` and then cleaning-up
///   and ensuring `completeOperation()` is called.

public class AsynchronousOperation : Operation {

    override public var isAsynchronous: Bool { return true }

    private let stateLock = NSLock()

    private var _executing: Bool = false
    override private(set) public var isExecuting: Bool {
        get {
            return stateLock.withCriticalScope { _executing }
        }
        set {
            willChangeValue(forKey: "isExecuting")
            stateLock.withCriticalScope { _executing = newValue }
            didChangeValue(forKey: "isExecuting")
        }
    }

    private var _finished: Bool = false
    override private(set) public var isFinished: Bool {
        get {
            return stateLock.withCriticalScope { _finished }
        }
        set {
            willChangeValue(forKey: "isFinished")
            stateLock.withCriticalScope { _finished = newValue }
            didChangeValue(forKey: "isFinished")
        }
    }

    /// Complete the operation
    ///
    /// This will result in the appropriate KVN of isFinished and isExecuting

    public func completeOperation() {
        if isExecuting {
            isExecuting = false
        }

        if !isFinished {
            isFinished = true
        }
    }

    override public func start() {
        if isCancelled {
            isFinished = true
            return
        }

        isExecuting = true

        main()
    }

    override public func main() {
        fatalError("subclasses must override `main`")
    }
}

/*
 Copyright (C) 2015 Apple Inc. All Rights Reserved.
 See LICENSE.txt for this sample’s licensing information

 Abstract:
 An extension to `NSLock` to simplify executing critical code.

 From Advanced NSOperations sample code in WWDC 2015 https://developer.apple.com/videos/play/wwdc2015/226/
 From https://developer.apple.com/sample-code/wwdc/2015/downloads/Advanced-NSOperations.zip
 */

import Foundation

extension NSLock {

    /// Perform closure within lock.
    ///
    /// An extension to `NSLock` to simplify executing critical code.
    ///
    /// - parameter block: The closure to be performed.

    func withCriticalScope<T>( block: (Void) -> T) -> T {
        lock()
        let value = block()
        unlock()
        return value
    }
}

这种模式还有其他可能的变化,但只是确保你(a)对异步返回true;和(b)您张贴必要的isFinished和正在执行KVN,如概述Concurrency Programming Guide: Operation Queues的并发执行配置操作部分。

猜你在找的Swift相关文章