2017-02-05 4 views
1

URLSession.shared.downloadTaskリクエストを実行しましたが、downloadTaskが実行されたのと同じスレッドでコードを実行したいとします。例:スレッドインスタンスでブロックを実行するには?

func sample() { 
    let thread = Thread.current 

    URLSession.shared.downloadTask(with: file) { 
     someFunc() //How to execute on thread variable? 
    }.resume() 
} 

完了ハンドラでは、バックグラウンドスレッドで実行されています。しかし、someFunc()と同じスレッドsample()が呼び出されました。私はThread.current.async {...}のようなものは、私はこれを行うことができますするにはどうすればよい:あなたは、特定のThread上で何かを実行したい場合は

func sample() { 
    let thread = Thread.current 

    URLSession.shared.downloadTask(with: file) { 
     thread.async { someFunc() } //Doesn't compile 
    }.resume() 
} 

答えて

1

、あなたはむしろちょうどこのGCDのAPIを使用しますが、ではないでしょう:

perform(#selector(someMethod), on: thread, with: nil, waitUntilDone: false, modes: [RunLoopMode.commonModes.rawValue]) 

もちろんのこと、例えば、あなたが実行ループでスレッドを作成することを前提としています

let thread = Thread(target: self, selector: #selector(threadEntryPoint), object: nil) 
thread.start() 

func threadEntryPoint() { 
    autoreleasepool { 
     Thread.current.name = "com.domain.app.background" 
     let runLoop = RunLoop.current 
     runLoop.add(NSMachPort(), forMode: .defaultRunLoopMode) 
     runLoop.run() 
    } 
} 

詳細については、Threading Programming Guideを参照してください。

個人的には、人間的に可能であれば私は個人的にGCDにとどまりますが、他の場所ではそれを排除する独自の要件があると言っています。

+0

これは問題を解決する可能性がありますが、スレッドは非常に低レベルで複雑です。 'perform on:'を介してこの特定のスレッドに渡される 'sample'メソッドの呼び出しを変更する必要があります。 'sample'と' someFunc'の間の他のスレッドによって作成されたアウトオブオーダーのイベントに対処しなければならないかもしれません...同じ方法は、 'OperationQueue'のような高レベルのAPIを使用してアーカイブすることができます。 – andih

+0

私は同意します。なぜなら、「できればGCDを使用する」ことで閉じたからです。しかし、これは操作キューの良いユースケースではありません。そして、あなたの答えのように、呼び出しスレッドをブロックすることは決して良い考えではありません。 – Rob

+0

あなたが正しいです、ブロックアプローチは避けなければなりません。ブロッキングを回避する別のアプローチは、依存する操作を使用することです。 – andih

0

Thread.current.asyncのように、コンパイルされない理由はありません。

samplesomeFuncを同じスレッドで実行する場合は、OperationOperationQueueを使用できます。この方法の欠点は、 が1つのスレッドをブロックしていることです。

var myQueue:OperationQueue = { 
    let q = OperationQueue() 
    q.name = "downloadQueue" 
    // if you want to limit concurrent operation 
    q.maxConcurrentOperationCount = 5 
    return q 
}() 


class DowloadOperation :Operation { 

    enum State { 
     case Ready, Executing, Finished 
     // ... 
    } 

    var state = State.Ready { 
     willSet { 
      ... 
     } 
     didSet { 
      ... 
     } 
    }  

    override func start() { 
     if self.isCancelled { 
      state = .Finished 
     } else { 
      state = .Ready 
      main() 
     } 
    } 

    override var isFinished: Bool { 
     get { 
      return state == .Finished 
     } 
    } 

    override var isAsynchronous: Bool { 
     get { 
      return true 
     } 
    } 

    override var isExecuting: Bool { 
     get { 
      return state == .Executing 
     } 
    } 


    override func main() { 
     if self.isCancelled { 
      self.state == .Finished 
      return 
     } 

     state = .Executing 

     URLSession.shared.downloadTask(with: file) { 
      // ... 
      state = .Finished 
     } 

     }.resume() 
    } 
} 

func someFunc() { 
    ... 
} 

// sample and someFunc are executed on the same thread 
// you loose the advantage of the async download. 
func sample() { 
    downloadOp = DownloadOperation() 
    myQueue.addOperation(downloadOp) 
    downloadOp.waitUntilFinished() 
    someFunc() 
} 
+0

言うまでもなく、非同期の 'Operation'サブクラス(素晴らしいパターンです)を行う場合、読者は必要なキー値通知を行う必要があることに注意する必要があります。私は 'willSet'と' didSet'に省略記号がある場所でそれを行うことを意図していると確信していますが、それは本質的な詳細なのか、それとも依存関係などは単純に機能しません。 – Rob

関連する問題