【问题标题】:NSOperation running on main threadNSOperation 在主线程上运行
【发布时间】:2016-12-19 17:49:45
【问题描述】:

我使用this 指南让我的应用程序使用 NSOperationQueue 和 NSOperations。但是我的代码仍然在主线程上运行,不管:S?我必须说我是 NSOperation 的新手,我认为这是我错过的一件小事。

class CountryFetcher: NSObject{
    var operation: NSOperation?
    var alamoFireQueue: NSOperationQueue{
        let val = NSOperationQueue()
        val.maxConcurrentOperationCount = 10
        val.name = "Alamofire Downloading Queue"
        return val
    }

    func getCountries(){
        operation = CountryProcessor(URLString: (BASE_URL + "countries/"+CAT_STAMPS))
        alamoFireQueue.addOperation(operation!)
    }
}

class CountryProcessor : ConcurrentOperation {
    let URLString: String
    weak var request: Alamofire.Request?


    init(URLString: String) {
        self.URLString = URLString
        super.init()
    }

    override func main() {
        request = Alamofire.request(.GET, URLString).responseJSON { response in
            if let dataResponse = response.data{
                var test: NSArray?
                do{
                    test = try NSJSONSerialization.JSONObjectWithData(dataResponse, options: NSJSONReadingOptions()) as! NSArray
                }catch let error as NSError{
                    print(error.localizedDescription)
                }
                for _ in 1...100{
                        NSLog("main thread? %@", NSThread.isMainThread() ? "YES" : "NO");
                }
            }
            self.completeOperation()
        }
    }

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

这是 ConcurrentOperation 类。我从上面链接中的帖子中复制了它。

class ConcurrentOperation : NSOperation {

    override var asynchronous: Bool {
        return true
    }

    override var concurrent: Bool{
        return true
    }

    private var _executing: Bool = false
    override var executing: Bool {
        get {
            return _executing
        }
        set {
            if (_executing != newValue) {
                self.willChangeValueForKey("isExecuting")
                _executing = newValue
                self.didChangeValueForKey("isExecuting")
            }
        }
    }

    private var _finished: Bool = false;
    override var finished: Bool {
        get {
            return _finished
        }
        set {
            if (_finished != newValue) {
                self.willChangeValueForKey("isFinished")
                _finished = newValue
                self.didChangeValueForKey("isFinished")
            }
        }
    }

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

    func completeOperation() {
        executing = false
        finished  = true
    }

    override func start() {
        if (cancelled) {
            finished = true
            return
        }

        executing = true

        main()
    }
}

当我执行这段代码时,它一直说它在主线程上运行:2016-08-12 18:25:45.799 Stamp Catalague Preloader[1807:31357] 主线程?是的。

这是怎么回事?感谢您的帮助;

【问题讨论】:

  • 您可能已经从here 获得了NSOperation 子类,但我已经对其进行了更新以同步executingfinished getter 和setter。请参阅 Multicore Considerations 讨论,其中讨论了同步这些的重要性。
  • 另外,由于您使用的是responseJSON,因此无需致电NSJSONSerialization。这已经为你完成了。 (这就是我们使用responseJSON的原因,所以我们不必担心自己解析它。)只需使用response.result.value即可。

标签: swift multithreading nsoperation nsoperationqueue


【解决方案1】:

问题在于 Alamofire 将其完成处理程序分派到主队列(理论上是他们想让您更轻松地更新 UI 和/或模型)。

如果您想为完成处理程序使用不同的队列,请将队列参数提供给responseresponseJSON 方法。

例如,有一些属性:

var completionHandlerQueue = dispatch_queue_create("com.domain.completionhandler", nil)

然后,当你执行请求时:

Alamofire.request(.GET, URLString).responseJSON(queue: completionHandlerQueue) { response in
    guard let test = response.result.value else {
        print("no data")
        print(response.result.error)
        return
    }

    // do something with `test` here
    print(test)

    NSLog("main thread? %@", NSThread.isMainThread() ? "YES" : "NO");
}

这提出了一个问题,即您是否真的关心完成处理程序是否在主队列上被调用。当然,如果你在那里做一些计算密集型的事情,那么一定要指定一个不同的队列。但是一个操作没有理由不能在主队列上执行它的一些任务。事实上,有时让完成处理程序在主队列上运行非常有用,这样您就无需同步模型更新和/或将 UI 更新分派到主队列。

为了更进一步,我们必须问一下使用NSOperation 的目的是什么。如果目标只是享受请求的异步处理,则不需要NSOperation。但是如果 (a) 你使用NSOperation 来管理不同操作的依赖关系;并且 (b) 你没有使用后台会话,那么,无论如何,将你的请求包装在操作中。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-03
    • 1970-01-01
    • 1970-01-01
    • 2020-10-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多