关于CFNetwork,CFReadStreamOpen和CFRunLoopRun的困惑

时间:2011-09-21 22:30:10

标签: iphone ios cfnetwork cfrunloop

当你意识到你不知道发生了什么时,那种沉闷的感觉......

我在网络代码中使用此代码已近两年没有问题。

if (!CFReadStreamOpen(myReadStream)) {
    CFStreamError myErr = CFReadStreamGetError(myReadStream);
    if (myErr.error != 0) {
    // An error has occurred.
        if (myErr.domain == kCFStreamErrorDomainPOSIX) {
        // Interpret myErr.error as a UNIX errno.
            strerror(myErr.error);
        } else if (myErr.domain == kCFStreamErrorDomainMacOSStatus) {
            OSStatus macError = (OSStatus)myErr.error;
            }
        // Check other domains.
    }
}

我认为它最初是基于此处给出的代码示例:

http://developer.apple.com/library/mac/#documentation/Networking/Conceptual/CFNetwork/CFStreamTasks/CFStreamTasks.html

但是,我最近注意到,有些连接失败,因为CFReadStreamOpen返回false但错误代码为0.在盯着上面的链接后,我注意到了CFRunLoopRun()语句,并添加了它:

if (!CFReadStreamOpen(myReadStream)) {
    CFStreamError myErr = CFReadStreamGetError(myReadStream);
    if (myErr.error != 0) {
    // An error has occurred.
        if (myErr.domain == kCFStreamErrorDomainPOSIX) {
        // Interpret myErr.error as a UNIX errno.
            strerror(myErr.error);
        } else if (myErr.domain == kCFStreamErrorDomainMacOSStatus) {
            OSStatus macError = (OSStatus)myErr.error;
            }
        // Check other domains.
    } else
        // start the run loop
        CFRunLoopRun();
}

这解决了连接问题。但是,我的应用程序开始显示随机问题 - 界面有时没有响应,或者没有绘图,文本字段不可编辑,那种东西。

我已经阅读了CFReadStreamOpen和运行循环(具体来说,主运行循环自行运行,除非我自己在辅助线程中设置它,否则我不应运行运行循环 - 我据我所知,不是。但我仍然对上面发生的事情感到困惑。具体做法是:

1)为什么CFReadStreamOpen有时会返回FALSE且错误代码为0?这究竟意味着什么?

2)CFRunLoopRun调用在上面的代码中实际执行了什么操作?为什么示例代码会进行调用 - 如果此代码在主线程中运行,我不应该运行运行循环?

1 个答案:

答案 0 :(得分:1)

我想我会尽可能地回答我自己的问题。

1)在我的代码中,至少CFReadStreamOpen似乎总是返回false。 The documentation有点令人困惑,但我读到它意味着流尚未打开,但将在运行循环中稍后打开。

2)我正在进行的大多数调用都发生在主线程中,其中运行循环已经在运行,因此调用CFRunLoopRun是不必要的。给我带来问题的调用发生在一个块内,这显然产生了一个新的线程。这个新线程没有启动新的运行循环 - 所以除非我明确地运行新线程的运行循环,否则流将永远不会打开。

如果我在已经运行的运行循环的线程上调用CFRunLoopRun(),我仍然不会100%清楚会发生什么,但显然不是很好。

我最终放弃了自制的网络代码并切换到ASIHTTPRequest,无论如何我都在考虑这样做。