Swift 2-iOS-Despacho a la secuencia de origen
multithreading swift2 (2)
Así que tengo una aplicación que dispara una serie de eventos asincrónicos y luego escribe los resultados en un búfer. El problema es que quiero que el buffer se escriba sincrónicamente (en el hilo que generó el proceso asincrónico)
código esqueleto es como tal
let Session = NSURLSession.sharedSession()
let TheStack = [Structure]()
//This gets called asynchronously, e.g. in threads 3,4,5,6,7
func AddToStack(The Response) -> Void {
TheStack.insertAt(Structure(The Response), atIndex: 0))
if output.hasSpaceAvailable == true {
// This causes the stream event to be fired on mutliple threads
// This is what I want to call back into the original thread, e.g. in thread 2
self.stream(self.output, handleEvent: NSStreamEvent.hasSpaceAvailable)
}
}
// This is in the main loop, e.g. thread 2
func stream(aStream: NSStream, handleEvent: NSStreamEvent) {
switch(NSStreamEvent) {
case NSStreamEvent.OpenCompleted:
// Do some open stuff
case NSStreamEvent.HasBytesAvailable:
Session.dataTaskWithRequest(requestFromInput, completionHandler: AddToStack)
case NSStreamEvent.HasSpaceAvailable:
// Do stuff with the output
case NSStreamEvent.CloseCompleted:
// Close the stuff
}
}
El problema es que el hilo que llama es dataTaskWithRequest
está en hilo, por ejemplo, 3. El controlador de finalización dispara en muchos subprocesos diferentes y provoca el case NSStreamEvent.HasSpaceAvailable:
para ejecutarse en el hilo 3, más todos los hilos en los que estaban.
Mi pregunta es: ¿cómo lo hago para que self.stream(self.output, handleEvent: NSStreamEvent.hasSpaceAvailable)
se self.stream(self.output, handleEvent: NSStreamEvent.hasSpaceAvailable)
3, o cualquiera que sea el hilo original para evitar este tropezar entre sí en la salida fase.
¡Gracias por adelantado!
NOTA: El hilo que contiene el manejo de entrada / salida se creó con NSThread.detachNewThreadSelector
Muy bien, para el curioso espectador I, con ayuda de los comentarios a la pregunta, he descubierto cómo hacer lo que originalmente pedí en la pregunta (si esto finalmente se reescribe para usar GCD es una pregunta diferente)
La solución (con un alcance ligeramente mayor en el código) es usar performSelector con un hilo específico.
final class ArbitraryConnection {
internal var streamThread: NSThread
let Session = NSURLSession.sharedSession()
let TheStack = [Structure]()
//This gets called asynchronously, e.g. in threads 3,4,5,6,7
func AddToStack(The Response) -> Void {
TheStack.insertAt(Structure(The Response), atIndex: 0))
if output.hasSpaceAvailable == true {
// This causes the stream event to be fired on multiple threads
// This is what I want to call back into the original thread, e.g. in thread 2
// Old way
self.stream(self.output, handleEvent: NSStreamEvent.hasSpaceAvailable)
// New way, that works
if(streamThread != nil) {
self.performSelector(Selector("startoutput"), onThread: streamThread!, withObject: nil, waitUntilDone: false)
}
}
}
func open -> Bool {
// Some stuff
streamThread = NSThread.currentThread()
}
final internal func startoutput -> Void {
if(output.hasSpaceAvailable && outputIdle) {
self.stream(self.output, handleEvent: NSStreamEvent.HasSpaceAvailable)
}
}
// This is in the main loop, e.g. thread 2
func stream(aStream: NSStream, handleEvent: NSStreamEvent) {
switch(NSStreamEvent) {
case NSStreamEvent.OpenCompleted:
// Do some open stuff
case NSStreamEvent.HasBytesAvailable:
Session.dataTaskWithRequest(requestFromInput, completionHandler: AddToStack)
case NSStreamEvent.HasSpaceAvailable:
// Do stuff with the output
case NSStreamEvent.CloseCompleted:
// Close the stuff
}
}
}
Entonces use performSelector en el objeto con el selector y use el onThread para indicarle a qué hilo pasar. Reviso ambos antes de realizar el selector y antes de hacer la llamada para asegurarme de que la salida tenga espacio disponible (asegúrese de que no me tropiece)
No me deja comentar sobre el hilo anterior (esto es lo que me pasa por acecho), pero una cosa a tener en cuenta es que su código actual podría bloquear su UI si usa waitUntilDone
o performBlockAndWait
.
Si vas por esa ruta, debes estar absolutamente seguro de que no llamas esto desde el tema principal o tienes un caso alternativo que genera un nuevo hilo.