2017-02-05 4 views
1

-je effectuer URLSession.shared.downloadTask demande, mais voudrait exécuter du code sur le même thread le downloadTask a été exécuté sur. Par exemple:Comment exécuter un blocage sur une instance de thread?

func sample() { 
    let thread = Thread.current 

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

Dans le gestionnaire d'achèvement downloadTask, il est en cours d'exécution sur un fil de fond. Cependant, je voudrais appeler someFunc() sur le même fil sample() a été appelé. Comment dois-je faire quelque chose comme Thread.current.async {...} je peux le faire:

func sample() { 
    let thread = Thread.current 

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

Répondre

1

Si vous voulez exécuter quelque chose sur un particulier Thread, vous n'utiliser cette API GCD, mais simplement:

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

ce suppose bien sûr que vous avez créé un fil avec une boucle d'exécution, par exemple:

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

et

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

Pour plus d'informations, consultez le Threading Programming Guide.

Personnellement, je personnellement rester dans GCD si humainement possible, mais vous avez dit ailleurs que vous avez une exigence unique qui empêche cela.

+0

Cela peut résoudre le problème, mais les threads sont de très bas niveau et compliqués. Vous devez modifier l'invocation de la méthode 'sample' à transmettre à ce thread spécifique via' perform on: '. Vous pourriez avoir à faire face à des événements d'ordre créés par d'autres threads entre 'et' someFunc' Par échantillon ... La même chose peut être archivé en utilisant les API de haut niveau comme 'OperationQueue' qui devrait être le meilleur moyen. – andih

+0

Je suis d'accord, c'est pourquoi j'ai fermé avec "utiliser GCD si vous le pouvez". Ce n'est cependant pas un bon cas d'utilisation pour les files d'attente d'opérations. Et bloquer le fil d'appel, comme vous le faites dans votre réponse, n'est jamais une bonne idée. – Rob

+0

Vous avez raison, l'approche de blocage doit être évitée. Une autre approche qui évite le blocage serait d'utiliser des opérations dépendantes. – andih

0

Il n'y a rien comme Thread.current.async qui est la raison pour laquelle il ne compile pas.

Si vous souhaitez exécuter sample et someFunc sur le même fil que vous pouvez utiliser un Operation et un OperationQueue. Inconvénient de cette approche, vous ar bloquant un thread.

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

Inutile de dire que si vous faites une sous-classe asynchrone 'Operation' (qui est un excellent motif), les lecteurs doivent noter qu'ils doivent faire les notifications de valeur-clé nécessaires. Je suis sûr que vous aviez l'intention de le faire lorsque vous avez vos ellipses dans 'willSet' et' didSet', mais c'est un détail essentiel ou bien des dépendances, et autres, ne fonctionneront tout simplement pas. – Rob