Swift 2-iOS-分派回原始线程

Swift 2-iOS-分派回原始线程,ios,multithreading,swift,swift2,nsthread,Ios,Multithreading,Swift,Swift2,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 {

因此,我有一个应用程序,它触发一系列异步事件,然后将结果写入缓冲区。问题是我希望同步写入缓冲区(在产生异步进程的线程中)

骨架代码就是这样

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
   }
}
问题是调用is
dataTaskWithRequest
的线程在线程中,例如3。完成处理程序在许多不同的线程中激发,并导致
case nsstreamvent.hasspaceavable:
在线程3中运行,以及它们所在的所有线程

我的问题是:如何使
self.stream(self.output,handleEvent:NSStreamEvent.hasspaceavable)
在线程3中被调用,或者说原始线程是为了防止在输出阶段彼此发生这种跳脱

提前谢谢


注意:包含输入/输出处理的线程是使用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告诉它要传递到哪个线程。我在执行选择器之前和调用之前都进行了检查,以确保输出有可用空间(确保我不会绊倒自己)

它不会让我对上面的线程发表评论(这是我通过潜伏获得的),但需要注意的是,如果使用
waitUntilDone
performBlockAndWait
,当前代码可能会使UI死锁


如果您选择该路线,您需要绝对确保您没有从主线程调用此命令,或者没有产生新线程的回退情况。

创建您自己的队列并将应该使用的队列传递给您的编写器如何?(我说“排队”是因为你用gcd做了标记。)我想在下班前大约5分钟这样做。创建线程/队列并将所有输出导入该线程/队列。这样,即使有多个线程在调用,它们也不会同时尝试执行。我现在要休息到星期二,所以如果这是我要走的路线,我会让你知道它是如何运行的。我已经有了一个由NSThread.detachNewThreadSelector创建的NSThread。这是我需要重新调用的线程。我担心,如果您想要一个正确使用GCD的流的好例子(通过CFStream,但这与NSStream非常相似),调度可能实际上会恶化问题(在所有操作完成之前流关闭),请参阅CocoaAsyncSocket中的GCD代码。这是我所知道的管理网络套接字的最好的库。如果可能,我会在GCD上使用
performSelector
系列,因为它隐藏并处理
waituntldone
,您可能会发现以下讨论很有用:。我会坚持使用
performSelector
,因为它包装了GCD,并解决了从相同或不同队列进行调度的难题。感兴趣的是
waitUntilDone:false
,我通常喜欢
true
,以确保正确的操作顺序。是的,我已经用
performSelector
完成了项目测试。由于这些线程的生成方式,每个线程通常只有一个线程(
dataTaskWithRequest
处理该线程)。因此,通过使其
false
我允许在数据添加到缓冲区队列后清除线程。仍然需要经过一些测试,以确保在投入到更大的项目中时,一切都保持在一起。你似乎完全掌握了控制权!我使用
performSelector
performBlock
的经验是,我通常会后悔在这里或那里节省毫秒,并且必须恢复到
waituntldone
performBlockAndWait
以确保健壮性和可预测性。这对任何读者来说都是一个好消息
waitUntilDone=false
将是一个例外,而不是标准。这是一个我没有在代码中明确处理的好问题,在我的情况下,
dataTaskWithRequest
的完成处理程序永远不会出现在主GUI线程中。无论如何,这是一个很好的观点。既然你是我以外唯一回答这个问题的人,那就享受赏金吧!