12

我遵循了设置套接字流指南,并在课堂上有效地复制了该代码。无论我尝试什么,委托方法似乎都没有被调用。

在我的头文件中(基本上):

@interface myClass : NSObject <NSStreamDelegate> {
    NSInputStream *inputStream;
    NSOutputStream *outputStream;
}
- (void)connect;
@end;

连接方法:

- (void)connect {
    CFReadStreamRef readStream;
    CFWriteStreamRef writeStream;

    CFStreamCreatePairWithSocketToHost(kCFAllocatorDefault, (CFStringRef)@"host.example.com", 1234, &readStream, &writeStream);

    inputStream = (NSInputStream *)readStream;
    outputStream = (NSOutputStream *)writeStream;
    [inputStream setDelegate:self];
    [outputStream setDelegate:self];
    [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
    [inputStream open];
    [outputStream open];
}

还尝试使用CFStreamCreatePairWithSocketToCFHost()[NSStream getStreamsToHost:port:inputStream:outputStream:- 都得到完全相同的结果。

我在connect方法的开头设置了一个断点,遍历每一行,每个指针都是有效的,并且似乎指向正确的对象。

在 GDB 中,setDelegate调用后按预期po [inputStream delegate]打印<myClass: 0x136380>,因此它已正确设置委托。

对于我的一生,我无法弄清楚为什么它拒绝stream:handleEvent:在我的班级上调用该方法:

- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode {
    NSLog(@"got an event");
}

希望我错过了一些非常简单和明显的东西,第二双眼睛可以发现我的错误。

提前感谢任何有耐心并花时间阅读本文的人!

4

2 回答 2

29

在这样的行中:

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

而不是使用[NSRunLoop currentRunLoop]我将其更改为[NSRunLoop mainRunLoop].

编辑 2011-05-30:

这不起作用的原因是因为我在后台线程中通过+[NSThread detachNewThreadSelector:toTarget:withObject:].

这样做会创建一个新的运行循环,在阅读了运行循环开发人员文档后,我发现您需要告诉 NSRunLoop 手动运行。

在与主线程相同的运行循环中运行它在性能上很好,尽管我可以通过编写包装类并在后台线程上运行所有网络 I/O 来挤出更多性能。

于 2011-02-08T23:46:31.250 回答
9

该解决方案仅在线程 0 上没有阻塞工作时才有效。这通常没问题,但更好的解决方案是创建一个新线程(即使用类方法按需创建线程)然后入队在那个线程上。IE

+ (NSThread *)networkThread {
    static NSThread *networkThread = nil;
    static dispatch_once_t oncePredicate;

    dispatch_once(&oncePredicate, ^{
        networkThread =
             [[NSThread alloc] initWithTarget:self
                                     selector:@selector(networkThreadMain:)
                                       object:nil];
        [networkThread start];
    });

    return networkThread;
}

+ (void)networkThreadMain:(id)unused {
    do {
        @autoreleasepool {
            [[NSRunLoop currentRunLoop] run];
        }
    } while (YES);
}

- (void)scheduleInCurrentThread
{
    [inputstream scheduleInRunLoop:[NSRunLoop currentRunLoop]
                           forMode:NSRunLoopCommonModes];
}

有了这个,您可以使用以下方法安排输入流:

[self performSelector:@selector(scheduleInCurrentThread)
             onThread:[[self class] networkThread]
           withObject:nil
        waitUntilDone:YES];

这将允许您运行您的网络操作,而不必再担心死锁。

于 2012-04-10T17:51:54.523 回答