Swift 2 - iOS - 分派回原始线程
Swift 2 - iOS - Dispatch back to originating thread
所以我有一个应用程序可以触发一系列异步事件,然后将结果写入缓冲区。问题是我希望同步写入缓冲区(在产生异步进程的线程中)
骨架代码就是这样
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
}
}
问题是调用的线程 dataTaskWithRequest
在线程中,比如说,3。完成处理程序在许多不同的线程中触发并导致 case NSStreamEvent.HasSpaceAvailable:
在线程中 运行 3,加上它们存在的所有线程。
我的问题是:如何才能在线程 3 中调用 self.stream(self.output, handleEvent: NSStreamEvent.hasSpaceAvailable)
,或者无论原始线程是什么,以防止在输出阶段相互绊倒。
提前致谢!
注意:包含 input/output 处理的线程是使用 NSThread.detachNewThreadSelector
创建的
好吧,对于好奇的旁观者我,在对问题的评论的帮助下,我已经想出了如何做我最初在问题中提出的问题(是否最终被重写为使用 GCD 是一个不同的问题)
解决方案(稍微增加代码范围)是对特定线程使用 performSelector。
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
}
}
}
所以在带有选择器的对象上使用 performSelector 并使用 onThread 告诉它要传递给哪个线程。我在执行选择器之前和调用之前都进行了检查,以确保输出有 space 可用(确保我不会绊倒自己)
它不会让我对上面的线程发表评论(这是我潜伏的结果),但需要注意的一件事是,如果您使用,您当前的代码可能会使您的 UI 死锁waitUntilDone
或 performBlockAndWait
。
如果你走那条路,你需要绝对确定你不会从 mainThread 调用它或者有一个产生新线程的后备案例。
所以我有一个应用程序可以触发一系列异步事件,然后将结果写入缓冲区。问题是我希望同步写入缓冲区(在产生异步进程的线程中)
骨架代码就是这样
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
}
}
问题是调用的线程 dataTaskWithRequest
在线程中,比如说,3。完成处理程序在许多不同的线程中触发并导致 case NSStreamEvent.HasSpaceAvailable:
在线程中 运行 3,加上它们存在的所有线程。
我的问题是:如何才能在线程 3 中调用 self.stream(self.output, handleEvent: NSStreamEvent.hasSpaceAvailable)
,或者无论原始线程是什么,以防止在输出阶段相互绊倒。
提前致谢!
注意:包含 input/output 处理的线程是使用 NSThread.detachNewThreadSelector
创建的好吧,对于好奇的旁观者我,在对问题的评论的帮助下,我已经想出了如何做我最初在问题中提出的问题(是否最终被重写为使用 GCD 是一个不同的问题)
解决方案(稍微增加代码范围)是对特定线程使用 performSelector。
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
}
}
}
所以在带有选择器的对象上使用 performSelector 并使用 onThread 告诉它要传递给哪个线程。我在执行选择器之前和调用之前都进行了检查,以确保输出有 space 可用(确保我不会绊倒自己)
它不会让我对上面的线程发表评论(这是我潜伏的结果),但需要注意的一件事是,如果您使用,您当前的代码可能会使您的 UI 死锁waitUntilDone
或 performBlockAndWait
。
如果你走那条路,你需要绝对确定你不会从 mainThread 调用它或者有一个产生新线程的后备案例。