Swift 2 - iOS - 发送回原始线程

时间:2016-01-15 19:57:33

标签: 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 { 
   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),或者原始线程是什么,以防止在输出阶段相互跳闸。

提前致谢!

注意:包含输入/输出处理的线程是使用NSThread.detachNewThreadSelector创建的

2 个答案:

答案 0 :(得分:6)

好吧,对于好奇的旁观者我,在对问题的评论的帮助下,我已经想出如何做我最初在问题中提出的问题(这最终是否会被重写以使用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告诉它要传递给哪个线程。我在执行选择器之前和执行调用之前检查两者以确保输出有可用空间(确保我不会自己绊倒)

答案 1 :(得分:1)

它不允许我对上面的线程发表评论(这是我潜伏的内容),但有一件事需要注意的是,如果你使用{{1},你当前的代码可能会使你的UI死锁}或waitUntilDone

如果你走这条路,你需要绝对确定你不会从mainThread中调用它,或者有一个产生新线程的后备情况。