scheduleInRunLoop - 线程网络连接

时间:2012-07-28 08:22:42

标签: objective-c multithreading cocoa nsrunloop nsstream

我没有找到任何可以解释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?

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

请注意堆栈之间的区别。

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

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

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

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

Apples NSThread类和NSRunloop类使它变得容易,但由于运行循环与线程不同而引起混淆。 每个线程可以有一个运行循环,该循环至少循环一次,并在没有其他事情要做时立即返回。使用[NSRunLoop currentRunLoop],您需要的是您所在线程的运行循环,而不是在创建另一个线程。 因此,从同一线程两次调用完全相同的runloop会导致在同一线程中工作。这意味着如果某个部分正在阻塞,则说明您正在阻塞线程,因此同一线程中的其他部分也将等待。 (在最后一句话中,您可以将 thread runloop 交换,并且仍然相同,它阻塞了线程)

作为同时性问题,当输入和输出流应在“相同”时间工作时,通常涉及多个套接字端口。 NSInputStream是只读的,而NSOutputStream是只读的。 明智的做法是将输入流赋予自己的线程,原因是数据和定时可能会产生意外结果,而远程发件人的本性给您带来了无法控制的结果。您有责任定义一次调用一次后,runloop(各个线程)是否应保持活动状态。

这样做,您的输出流便在另一个线程中,即您要求其 current 运行循环的那个线程。 您无法创建或管理运行循环,只是要求它,因为每个线程都有一个,如果没有,则为您创建一个。

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

如果您不想根据需要创建服装NSThread子类,那么这里提到的一个简单解决方案可能也对您有用。 iOS how can i perform multiple 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东西。

答案 1 :(得分:-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;
    }
}