Путаница с CFNetwork, CFReadStreamOpen и CFRunLoopRun - PullRequest
3 голосов
/ 22 сентября 2011

Это чувство погружения, когда ты понимаешь, что понятия не имеешь, что происходит ...

Я использую этот код в своем сетевом коде почти два года без проблем.

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 Ответ

1 голос
/ 29 сентября 2011

Полагаю, я отвечу на свой вопрос столько, сколько смогу.

1) По крайней мере, в моем коде CFReadStreamOpen всегда возвращает false. Документация немного сбивает с толку, но я прочитал ее, чтобы обозначить, что поток еще не открыт, но будет открыт позже в цикле выполнения.

2) Большинство звонков, которые я делал, происходили в основном потоке, где цикл выполнения уже выполнялся, поэтому вызывать CFRunLoopRun не нужно. Звонок, который доставлял мне проблемы, происходил внутри блока, который, очевидно, породил новый поток. Этот новый поток не запустил новый цикл выполнения - поэтому поток никогда не откроется, если я не запустил явно цикл выполнения нового потока.

Я до сих пор не на 100% уверен в том, что произойдет, если я вызову CFRunLoopRun () в потоке с уже запущенным циклом выполнения, но это явно не хорошо.

Я закончил тем, что забросил свой домашний сетевой код и переключился на ASIHTTPRequest, что я все равно собирался сделать.

...