objective-c - NSInputStream 不调用委托(delegate)(流 :handleEvent:)

标签 objective-c ios sockets nsstream

我在网上搜索了很长时间...我没有找到问题的答案,所以我决定在这里发帖。 我尝试使用 NSStream 建立与 NNTP 服务器的连接。

在测试程序中,我打开流并发送一条消息。委托(delegate)方法 (stream:handleEvent:) 被调用两次用于输出流 (NSStreamEventOpenCompleted, NSStreamEventHasSpaceAvailable) 但从未 用于输入流!

为什么输入流从不调用委托(delegate)?有什么想法吗?

基本上,代码如下所示:

初始化和打开流:

CFReadStreamRef tmpiStream;
CFWriteStreamRef tmpoStream;

CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)SERVER, PORT, &tmpiStream, &tmpoStream);

iStream = (__bridge NSInputStream *) tmpiStream;
oStream = (__bridge NSOutputStream *)tmpoStream;

[iStream setDelegate:self];
[oStream setDelegate:self];

[iStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[oStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

[iStream open];
[oStream open];

发送消息:

NSData *data = [[NSData alloc] initWithData:[messageString dataUsingEncoding:NSASCIIStringEncoding]];
[oStream write:[data bytes] maxLength:[data length]];

接收消息:

-(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
    NSLog(@"EventCode: %i", eventCode);
    //switch-case-statement...(using constants - NSStreamEventOpenCompleted...)
}

包含该代码的类继承自 NSObjects 并实现了 NSStreamDelegate。 (带有 ARC 的 iOS5)

感谢您的帮助!

编辑: 我只是在像这样打开流后尝试“轮询” - 它正在工作:

while (![iStream hasBytesAvailable])
{}
uint8_t buffer[1024];
int len;
NSString *str = @"";

while ([iStream hasBytesAvailable]) 
{
    len = [iStream read:buffer maxLength:sizeof(buffer)];
    if (len > 0) 
    {
        NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSISOLatin1StringEncoding];

        if (output != nil) 
        {
            str = [str stringByAppendingString:output];
        }
    }
}
NSLog(@"Response: %@", str);

但是,可以肯定的是,我仍然需要一个更好的(异步)解决方案;)

最佳答案

我在这里找到了你的答案,我也有同样的问题。您的回答对我有用,但我认为这个效果更好:

How to use delegate in NSStream?

引用他的话:

The run loop isn't running long enough for the delegate method to be called.

Add:

[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];

right after you open the stream. This is only necessary in a program without a GUI -- otherwise the run loop would be spun for you.

所以我的看起来像这样:

[self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.inputStream open];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:30.0]];

编辑: 然后当你有数据时,例如,当 NSStreamEventEndEncountered 发生在委托(delegate)方法 stream:handleEvent 中时,我的所有数据都是完整的,我把它放在:

[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
CFRunLoopStop(CFRunLoopGetCurrent());
[theStream close];

它会在 30.0 秒之前或您设置的任何时间之前关闭运行循环。如果您的代码在 NSStreamHasBytesAvailable 中,那么您的答案将是相同的。

这让我仍然可以使用委托(delegate)方法并保持运行循环打开直到下载完成,而不用完全跳过委托(delegate)方法。

关于objective-c - NSInputStream 不调用委托(delegate)(流 :handleEvent:),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10889230/

相关文章:

c# - 每个线程的处理时间?

objective-c - Swift 类不符合带有错误处理的 Objective-C 协议(protocol)

objective-c - 获取本月的每个 NSDate 作为 NSString

ios - 访问 UIButton 的 subview 控件

ios - iOS 中的应用内购买有问题吗?

c - 套接字客户端不适用于 Kali

c - 在 TCP 服务器的读/写上实现 poll()

ios - 关于Core Data的两个问题

objective-c - 如何将自定义 View 添加到 NSSplitView 分隔线

objective-c - 在 iOs UIWebView 中摆脱链接点击 "flash"指示器