2016-08-12 7 views
1

私はthisガイドを使用して、アプリケーションでNSOperationQueueとNSOperationsを使用しました。しかし、私のコードはまだメインスレッドで実行されます:S?私はNSOperationには新しかったと言わなければならない、私はそれが私が逃した小さなことだと思う。メインスレッドで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年8月12日18:25:45.799スタンプCatalagueプリローダー[1807:31357]メインスレッド?はい。

どうしてですか?ご協力いただきありがとうございます;

+0

「NSOperation」サブクラスが[ここ](http://stackoverflow.com/questions/27021896/nsurlsession-concurrent-requests-with-alamofire/27022598#27022598)から取得されている可能性がありますが、それを更新しました'実行中の' getterと 'setter'メソッドを同期させます。会話する[Multicore Considerations](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がメインキューに完了ハンドラをディスパッチすることです(理論的には、UIやモデルを簡単に更新できるようにするためです)。

完了ハンドラに異なるキューを使用する場合は、responseまたはresponseJSONメソッドにキューパラメータを指定します。

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

これが完了ハンドラた場合、あなたが本当に気にするかどうかの問題を提起:たとえば

、いくつかのプロパティを持っている:あなたが要求を実行するときに

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

そして、メインキュー上で呼び出されるかどうかを示します。確かに、そこで計算的に集中的な何かをしているなら、是非、別のキューを指定してください。しかし、操作がメインキュー上でタスクのいくつかを実行できない理由はありません。実際、完了ハンドラをメインキューで実行させるだけでは、モデルの更新を同期させたり、UI更新をメインキューにディスパッチしたりする必要がなくなります。

さらに先に戻るには、NSOperationの使用目的が何であるか尋ねる必要があります。目的が非同期要求の処理を単に楽しむことであれば、NSOperationは必要ありません。しかし、(a)異なる操作の依存関係を管理するためにNSOperationを使用している場合。 (b)バックグラウンドセッションを使用していない場合は、操作で要求をラップします。

関連する問題