9

我还没有找到任何体面的文档来解释 NSStream 的线程处理过程。具体来说,让我们使用 NSInputStream。Objective-C 中的线程对我来说目前是一个谜,因为它看起来很简单。

我的问题主要是指这一行:

[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

您可以指定输入流将在其中运行的运行循环,我认为这很酷。问题是,如果我希望输入和输出流在它们自己的线程中运行,并且两者都在一个类中实例化,比如 Connection,那么你如何让它们在它们自己的线程中运行?

我问的原因是因为代表。以前我们会这样做[inputStream setDelegate:self],这意味着我们必须声明stream:handleEvent处理传入/传出数据。

所以最终我的问题是,如果你有一个设置输入和输出流的类,你如何将每个流线程化并将处理流事件的责任委托给当前类?

这里有一些代码可供选择:

[inputStream setDelegate:self];
[outputStream setDelegate:self];
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[inputStream open];
[outputStream open];

我在想以下几点:

  • 您不能将责任委派给当前类中的两个线程,您必须委派给单独的对象。
  • 一个线程可以同时处理两个流?(我个人不这么认为,因为输入/输出会同时运行)
  • 我想错了,您可以创建一个单独的运行循环并针对某个单独的线程调用 scheduleRunLoop 吗?

有任何想法吗?

4

2 回答 2

2

注意heapstack之间的区别。

每个线程都有自己的堆栈,但所有线程都访问同一个堆。

输入流需要自己的线程,因为在读取流而没有到达任何 EOF 时,如果没有新字符出现,线程会阻塞并因此等待。所以为了防止你的应用程序阻塞输入流需要一个单独的线程。

继续,因为委托不能是静态方法,您必须复制或至少同步使用缓冲区来返回结果。请记住,每个线程都有自己的堆栈,但都访问同一个堆。

NSStreamDelegate是一个界面,允许您指定谁将管理来自流的事件。因此,允许您拆分编程以处理流和处理它们的事件。正如您可以将委托视为指向函数的指针,您必须确保它们在运行时存在,这就是为什么它们通常与协议一起使用和定义的原因。但是调用委托的方法并不意味着调用另一个线程的函数。您仅将参数/对象应用于将/必须在运行时存在的另一个对象/类的方法。

AppleNSThread的 class 和NSRunloopclass 使它变得容易但令人困惑,因为 runloop 与线程不同。每个线程都可以有一个 runloop,它至少循环一次,并在无事可做时立即返回。当[NSRunLoop currentRunLoop]您要求您所在线程的运行循环时,您并没有创建另一个线程。因此,从同一个线程调用相同的 runloop 两次会导致在同一个线程中工作。这意味着如果一个部分正在阻塞,则您正在阻塞线程,因此同一线程中的其他部分也会等待。(在最后一句中,您可以将单词threadrunloop交换,它仍然是一样的,它正在阻塞线程)

作为同时性问题,当输入和输出流应该在“同时”工作时,通常会涉及多个套接字端口。NSInputStream是只读的 &NSOutputStream是只写的。明智的做法是为输入流提供自己的线程,因为远程发送者的性质给定的数据和时间可能会导致意外结果,而这是您无法控制的。您有责任定义运行循环(相应的线程)在调用一次后是否应该保持活动状态。

这样做你的输出流然后在一个/另一个线程中,你要求它的当前运行循环。您不能创建或管理运行循环,您只需要求它,因为每个线程都有一个,如果没有 - 为您创建一个。

在 iOS 上,您有许多解决方案可用于实现您的个人设计模式,用于同时输入和输出流。您也可以NSThread使用-performSelectorInBackground:SEL withObject:(nullable Id)which 实际上是NSObjectdefined in的扩展NSThread.h。但是最后一个不允许您定义特殊的运行模式。

如果您不想根据需要创建服装 NSThread 子类,这里提到的一个简单解决方案也可能对您有用。 iOS 我如何执行多个 NSInputStream[NSRunLoop currentRunloop]是分离的线程的运行循环。也可以使用块分离新线程

id<NSStreamDelegate> streamDelegate = //object that conforms to the protocol
[NSThread detachNewThreadWithBlock:^(void){
    NSInputStream *inputStream;
    [inputStream setDelegate:streamDelegate];
    // define your stream here
    [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
                   forMode:NSRunLoopCommonModes];
    [inputStream open];
}];`

PS:来自@Ping 的示例是一个开关,用于对两个流的事件进行交互,它不会同时进行流输入和输出。好吧,但是您可以在流及其事件上使用该示例,无论它们是否同时发生,典型的NSStreamDelegate东西。

于 2020-07-08T01:44:31.100 回答
-3
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
    switch (eventCode) {
        case NSStreamEventNone:
            break;
        case NSStreamEventOpenCompleted:
            break;
        case NSStreamEventHasBytesAvailable:
            [self _readData];
            break;
        case NSStreamEventHasSpaceAvailable:
            [self _writeData];
            break;
        case NSStreamEventErrorOccurred:
            break;
        case NSStreamEventEndEncountered:
            break;
        default:
            break;
    }
}
于 2014-02-11T15:35:54.853 回答