我已按照指南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");
}
希望我错过了一些非常简单明了的东西,第二双眼睛可以发现我的错误。
提前感谢任何有耐心并花时间阅读此内容的人!
答案 0 :(得分:27)
在这样的行中:
[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
我没有使用[NSRunLoop currentRunLoop]
,而是将其更改为[NSRunLoop mainRunLoop]
。
这不起作用的原因是因为我是通过+[NSThread detachNewThreadSelector:toTarget:withObject:]
在后台线程中设置套接字。
这样做会创建一个新的运行循环,在阅读run loop developer documentation之后我发现你需要告诉NSRunLoop手动运行。
在与主线程相同的运行循环中运行它在性能上很好,但我通过编写包装类并在后台线程上运行所有网络I / O来提高性能。
答案 1 :(得分:9)
如果&amp;只有当你没有在线程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];
这将允许您运行网络操作,而不必担心死锁。