NSStream 和 Sockets,未调用 NSStreamDelegate 方法
Posted
技术标签:
【中文标题】NSStream 和 Sockets,未调用 NSStreamDelegate 方法【英文标题】:NSStream and Sockets, NSStreamDelegate methods not being called 【发布时间】:2011-02-08 08:31:19 【问题描述】:我已按照指南 Setting Up Socket Streams 进行操作,并在课堂上有效地复制了该代码。无论我尝试什么,委托方法似乎都没有被调用。
在我的头文件中(基本上):
@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");
希望我错过了一些非常简单明了的东西,第二双眼睛可以发现我的错误。
提前感谢任何有耐心并花时间阅读本文的人!
【问题讨论】:
【参考方案1】:在这样的行中:
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
我没有使用[NSRunLoop currentRunLoop]
,而是将其更改为[NSRunLoop mainRunLoop]
。
编辑 2011-05-30:
这不起作用的原因是因为我正在通过+[NSThread detachNewThreadSelector:toTarget:withObject:]
在后台线程中设置套接字。
这样做会创建一个新的运行循环,在阅读run loop developer documentation 后我发现您需要告诉 NSRunLoop 手动运行。
在与主线程相同的运行循环中运行它的性能很好,尽管我可以通过编写包装类并在后台线程上运行所有网络 I/O 来挤出更多性能。
【讨论】:
@user102008 编辑了我的回复以解释。 你能贴出结束代码吗?出于某种原因,我将 [NSRunLoop currentRunLoop] 更改为 [NSRunLoop mainRunLoop] 并且连接在启动后不久就不会失败 你成功了!从主线程中删除我的套接字客户端后,我停止监听 inputStream(即使我的 outputStream 仍在工作,因为我可以在套接字服务器上进行监控)。我只是改变了输入流的运行循环和宾果游戏!赞成:) 您的问题和回答都帮助我知道去哪里,但我不确定如何使用简单的按钮开始和连接?? 非常感谢。我在使用 Monotouch 并在任务中打开套接字时遇到了同样的问题。使用主循环而不是当前(任务的线程)解决了这个问题。【参考方案2】:该解决方案仅在线程 0 上没有阻塞工作时才有效。这通常没问题,但更好的解决方案是创建一个新线程(即使用类方法按需创建线程)然后在该线程上排队。 即
+ (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];
这将允许您运行您的网络操作,而不必再担心死锁。
【讨论】:
感谢您的提示。我有另一个相关的问题。当流被写入时,用户可以继续在后台移动应用程序。我宁愿让流在后台运行。我尝试使用 beginBackgroundTask... 来实现这一点,但无论我做什么,当应用程序处于后台时,我都无法让我的图片上传工作。你这这一切都可能吗? 我们的一个教程应用程序可以做到这一点。如果您仍在寻求帮助,您可能想在parse.com/tutorials/anypic#post 上查看它,查看有关“保存 PFObject”的信息。虽然我们的框架隐藏了它,但后台任务中的位会进行网络调用。 这段代码是否定期充分耗尽自动释放池?-[NSRunLoop run]
的文档说它将重复调用 runMode:beforeDate:
。这意味着在这些调用之间不会耗尽自动释放池。以上是关于NSStream 和 Sockets,未调用 NSStreamDelegate 方法的主要内容,如果未能解决你的问题,请参考以下文章