runloop - 如何让 GCDAsyncSocket 中的 didReadData 在当前 RunLoop 中执行?

标签 runloop cocoaasyncsocket

我正在尝试获取一个使用 GCDAsyncSocket 的简单示例,并且发现我缺少某些理解,希望各位好心人可以帮助解释这一点。

我已经设置了下面的 GCDAsyncSocket 内容:

dispatch_queue_t mainQueue = dispatch_get_main_queue();
asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:mainQueue];

NSString *host = @"192.168.169.132";
uint16_t port = 2112;

DDLogInfo(@"Connecting to \"%@\" on port %hu...", host, port);
self.viewController.label.text = @"Connecting...";

NSError *error = nil;
if (![asyncSocket connectToHost:host onPort:port withTimeout:5.0 error:&error])
{
    DDLogError(@"Error connecting: %@", error);
    self.viewController.label.text = @"Oops";
}
else
{
    DDLogVerbose(@"Connecting...");
}


- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
    DDLogInfo(@"socket:%p didConnectToHost:%@ port:%hu", sock, host, port);
    self.viewController.label.text = @"Connected";

    // We're just going to send a test string to the server.

    NSString *myStr = @"testing...123...\r\n";
    NSData *myData = [myStr dataUsingEncoding:NSUTF8StringEncoding];

    [asyncSocket writeData:myData withTimeout:5.0 tag:0];
}

并且可以看到我的套接字测试服务器应用程序接收字符串

"testing...123...\r\n"

但是当我让套接字测试服务器发回一个字符串时,我天真地期望 didReadData 委托(delegate)执行

- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag

然而,残酷的现实迫使我明白这一点,直到我打电话

[asyncSocket readDataWithTimeout:5.0 tag:0];

... didReadData 委托(delegate)将不会被调用。

好的,没关系。我明白了。

阅读the documentation还有一些它明确指出

AsyncSocket is a RunLoop based TCP socket library.

所以现在我正在研究这个 RunLoop 东西,在我看来它就像 Message loop in Microsoft Windows 。由于 iOS 是一个事件/消息驱动的架构(就像 Win32 一样),那么我当前所处的默认主线程显然有它自己的消息循环来处理事件。

我现在的困惑是,iOS RunLoop 看起来像是一些单独的实体,必须与它一起工作才能使 GCDAsyncSocket 正常工作。

当它声明其默认的运行循环模式集是 NSDefaultRunLoopMode 时,它​​位于主线程中。

还困惑吗?

所以在 Win32 下我的通讯事件处理代码将如下所示:

while( sCOMport.hCOMport != INVALID_HANDLE_VALUE )  // ...while the COM port is open...
{
    // Wait for an event to occur on the port.
    WaitCommEvent( sCOMport.hCOMport, &dwCommStatus, NULL );

它当然会在它自己的线程中(尚未使用 GCDAsyncSocket 到达那里),但在某种程度上这将是它自己的“RunLoop”。

如何使用 GCDAsyncSocket 执行相同操作,以便我不会陷入使用 [asyncSocket readDataWithTimeout] 调用填充队列的轮询循环?

我觉得我们需要更好的例子来使用这个库。

最佳答案

好吧,我以某种方式让这个工作了。

请告诉我这是否违反某些“最佳实践”。

- (void)socket:(GCDAsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port
{
    // setup as normal...

    // then ...

    // Instigate the first read
    [asyncSocket readDataWithTimeout:-1 tag:0];

.
.
}

然后...当数据进来时...

- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
{
    // Do whatever you need to do with the data ...
.
.
.
    // and at the end ...
.
.
    // Always keep a 'read' in the queue.
    [asyncSocket readDataWithTimeout:-1 tag:0];
}

这将为您提供 RunLoop 操作,而无需使用计时器或其他结构。并且可以包含在它自己的线程中。 (但仍有待确定)

关于runloop - 如何让 GCDAsyncSocket 中的 didReadData 在当前 RunLoop 中执行?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7997200/

相关文章:

ios - 接收UDP广播数据

objective-c - 为什么我在iOS应用中收到EXC_ARITHMETIC错误?

iphone - 未调用 GCDAsynSocketDelegate didReadData 方法。使用 GCDAsynSocket

objective-c - Cocoa GUI 类如何在不调用 NSApplication 或 NSRunLoop 的情况下运行

ios - 在 _CFAutoreleasePoolPop 崩溃

swift - RunLoopObserver 和 RunLoopActivity

iphone - iOS 游戏和运行循环管理

ios - 找出 iOS 中什么阻塞了主线程/运行循环?

ios - semaphore_wait_trap、GCD 和 CocoaAsyncSocket