2016-08-12 4 views
1

Я использовал this руководство, чтобы использовать мое приложение NSOperationQueue и NSOperations. Но мой код по-прежнему работает на основном потоке независимо: S? Я должен сказать, что я новичок в NSOperation, я думаю, что это небольшая вещь, которую я пропустил.NSOperation running on main thread

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] Основная нить? ДА.

Как это происходит? Спасибо за вашу помощь;

+0

Возможно, вы получили подкласс 'NSOperation' из [здесь] (http://stackoverflow.com/questions/27021896/nsurlsession-concurrent-requests-with-alamofire/27022598#27022598), но я его обновил синхронизировать «исполняемые» и «готовые» геттеры и сеттеры. См. Раздел [Многоуровневые соображения] (https://developer.apple.com/library/ios/documentation/Cocoa/Reference/NSOperation_class/index.html#//apple_ref/doc/uid/TP40004591-RH2-SW17), в котором обсуждается о важности их синхронизации. – Rob

+0

Кроме того, поскольку вы используете 'responseJSON', нет необходимости вызывать' NSJSONSerialization'. Это уже сделано для вас. (Вот почему мы используем 'responseJSON', поэтому нам не нужно беспокоиться о его синтаксическом анализе.) Просто используйте' response.result.value'. – Rob

ответ

1

Проблема заключается в том, что Alamofire отправляет обработчики завершения в основную очередь (теория состоит в том, что они хотят облегчить вам обновление пользовательского интерфейса и/или модели).

Если вы хотите использовать другую очередь для обработчиков завершения, поставьте параметр очереди на методы response или responseJSON.

Например, есть свойство:

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"); 
} 

Это поднимает вопрос о том, действительно ли вы заботитесь, если обработчики завершения вызывается в основной очереди или нет. Конечно, если вы делаете что-то там с интенсивным вычислением, тогда, во что бы то ни стало, укажите другую очередь. Но нет причин, по которым операция не может выполнять некоторые из своих задач в главной очереди. На самом деле, иногда очень полезно использовать обработчики завершения в главной очереди, избавляя вас от необходимости синхронизации обновлений модели и/или отправки обновлений пользовательского интерфейса в основную очередь.

Чтобы отступить еще дальше, мы должны спросить, что означает использование NSOperation. Если целью является просто использовать асинхронную обработку запросов, то NSOperation не требуется. Но если (a) вы используете NSOperation для управления зависимостями разных операций; и (б) вы не используете фоновые сеансы, а затем, во что бы то ни стало, оберните свои запросы в операции.