So I have an application that fires a series of asynchronous events and then writes the results to a buffer. The problem is that I want the buffer to be written to synchronously (in the thread that spawned the asynchronous process)
skeleton code is as such
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
}
}
The problem is the thread that calls is dataTaskWithRequest
is in thread, say, 3. The completion handler fires in many different threads and causes case NSStreamEvent.HasSpaceAvailable:
to be running in thread 3, plus all the threads that they existed in.
My question is: How do I make it so that self.stream(self.output, handleEvent: NSStreamEvent.hasSpaceAvailable)
is called in thread 3, or what-ever the original thread was to prevent this tripping over of each other in the output phase.
Thanks in advance!
NOTE: The thread that contains the input/output handling was created with NSThread.detachNewThreadSelector
Alright, for the curious onlooker I, with aid from comments to the question I have figured out how to do what I originally asked in the question (whether or not this ultimately gets rewritten to use GCD is a different question)
The solution (with a slightly increased scope into the code) is to use performSelector with a specific thread.
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
}
}
}
So use performSelector on the object with the selector and use the onThread to tell it what thread to pass to. I check both before performing the selector and before doing the call to make sure that output has space available (make sure I don't trip over myself)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With