Swift 2 - iOS - 发回原始线程

问题描述:

因此,我有一个应用程序触发一系列异步事件,然后将结果写入缓冲区。的问题是,我想要的缓冲器被写入到同步(在产生了异步处理的线程)Swift 2 - iOS - 发回原始线程

骨架码作为这样

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,加上他们存在的所有线程。

我的问题是:如何使它self.stream(self.output, handleEvent: NSStreamEvent.hasSpaceAvailable)是在线程3中调用,或者永远是原始线程w以防止在输出阶段相互跳闸。

在此先感谢!

注:包含输入/输出处理与NSThread.detachNewThreadSelector

创建
+2

如何创建自己的队列并将应该使用的队列传递给作者? (我说“队列”是因为你用gcd标记的。) –

+1

在我不得不离开工作之前大约5分钟,我想过这么做。创建线程/队列并汇集所有输出。这种方式即使有多个线程正在调用,他们并不是都试图一次执行。我现在休息到星期二,所以如果这是我走的路线,我会让你知道它是怎么回事 – Ajwhiteway

+0

我已经有一个由NSThread.detachNewThreadSelector创建的NSThread。这是我需要回调的线程。我担心调度可能实际上会恶化问题(在所有事情完成之前关闭流) – Ajwhiteway

好吧,为好奇的旁观者我,与援助从评论的问题我已经找到了如何做我原来的线程在问题中询问(这是否最终被重写为使用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来告诉它传递给哪个线程。我在执行选择器之前以及在执行调用之前检查以确保输出具有可用空间(请确保我不会绊倒自己)

+0

我会坚持使用'performSelector',因为它包装了GCD,解决了从相同或不同队列派发的难题。我感兴趣的是'waitUntilDone:false',为了确保正确的操作顺序,我通常更喜欢'true'。 – SwiftArchitect

+0

是的,我已经使用'performSelector'封装了测试项目。由于这些产生的方式,通常每个线程只有一个线程('dataTaskWithRequest'处理这个线程)。因此,通过将其设置为'false',我可以在数据添加到缓冲区队列后允许清除线程。仍然需要进行一些测试,以确保将所有内容放在更大的项目中时都保持在一起。 – Ajwhiteway

+0

你似乎完全控制!我对'performSelector'和'performBlock'的经验是我通常会后悔保存几毫秒,并且为了鲁棒性和可预测性,必须恢复为'waitUntilDone'和'performBlockAndWait'。 – SwiftArchitect

它不会让我评论上面的线程(这是我潜藏的东西),但有一点需要注意的是,如果您使用waitUntilDoneperformBlockAndWait,您当前的代码可能会导致您的用户界面死锁。

如果你走这条路线,你需要绝对确定你不要从mainThread调用这个函数,或者有一个产生新线程的回退情况。

+0

这是一个很好的观点,我没有明确地在我的代码中处理过,在我的例子中'dataTaskWithRequest'的完成处理程序不应该在主GUI线程中结束。无论如何,一个好点。由于您是我自己以外唯一回答问题的人,请享受赏金奖励! – Ajwhiteway