Runloop 如何在当前运行循环中执行GCDAsyncSocket中获取didReadData?

Runloop 如何在当前运行循环中执行GCDAsyncSocket中获取didReadData?,runloop,cocoaasyncsocket,Runloop,Cocoaasyncsocket,我试图得到一个使用GCDAsyncSocket的简单示例,我发现我缺少一些理解,希望你们这些优秀的人能够帮助解释这一点 我已经在下面设置了GCDAsyncSocket: dispatch_queue_t mainQueue = dispatch_get_main_queue(); asyncSocket = [[GCDAsyncSocket alloc] initWithDelegate:self delegateQueue:mainQueue]; NSString *host = @"192

我试图得到一个使用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];
}
并且可以看到我的套接字测试服务器应用程序接收字符串

“正在测试…123…\r\n”

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

- (void)socket:(GCDAsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag
然而冷酷的现实迫使我学会了这一点,直到我打电话

[asyncSocket readDataWithTimeout:5.0 tag:0];
。。。不会调用didReadData委托

好的,没关系。我明白了

阅读更多的资料,它清楚地表明

AsyncSocket是一个基于RunLoop的TCP套接字库

现在我在看这个运行循环的东西,在我看来,它就像。由于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操作,而不使用计时器或其他构造。并且可以包含在它自己的线程中。(这仍然待定)

我知道这是一个老问题,已经有了一个公认的答案,但这是我的解决方案,我已经在我的一个应用程序中使用过:

连接到主机后,运行以下调度队列:

dispatch_queue_t alwaysReadQueue = dispatch_queue_create("com.cocoaasyncsocket.alwaysReadQueue", NULL);

dispatch_async(alwaysReadQueue, ^{
    while(![socket isDisconnected]) {
        [NSThread sleepForTimeInterval:5];
        [socket readDataWithTimeout:-1 tag:0];
    }
});

您可以使用相同的队列发送心跳请求,只是为了保持连接的活动状态。

我实际上也做了同样的事情。只需一次又一次地“重新排队”侦听器。我也很好奇这是不是一条路。像你一样,我也希望didReadData不需要做任何事情就可以被调用。这难道不是套接字的全部原因吗……我现在很困惑,我必须使用集群来接收数据,当数据到达时这是否会使套接字上的保留变强并阻止释放?我建议在(![weakSocket isDisconnected])时使用
,然后在睡眠后使用
\u strong GCDAsyncSocket*strongSocket=weakSocket然后检查它是否为零,如果为则断开。即使您使用对套接字的弱引用,有条件的
[socket isDisconnected]
也会导致NO,如果否定,则会导致YES,这意味着您的分派将永远不会退出。不过我可能弄错了。