NSStream и Sockets, методы NSStreamDelegate не вызываются - PullRequest
12 голосов
/ 08 февраля 2011

Я следовал инструкциям Настройка потоков сокетов и эффективно продублировал этот код в своем классе. Независимо от того, что я пробую, методы делегата просто не вызываются.

В заголовочном файле у меня (в основном):

@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");
}

Надеюсь, я упустил что-то действительно простое и очевидное, и вторая пара глаз может определить мою ошибку.

Заранее спасибо всем, кто проявил терпение и нашел время, чтобы прочитать это далеко!

Ответы [ 2 ]

27 голосов
/ 09 февраля 2011

В таких строках:

[inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

Вместо использования [NSRunLoop currentRunLoop] я изменил его на [NSRunLoop mainRunLoop].

РЕДАКТИРОВАТЬ 2011-05-30:

Причина, по которой это не сработало, заключается в том, что я настраивал сокеты в фоновом потоке с помощью +[NSThread detachNewThreadSelector:toTarget:withObject:].

При этом был создан новый цикл выполнения, который после прочтения разработчика цикла выполнениядокументация Я обнаружил, что вам нужно указать, чтобы NSRunLoop запускался вручную.

Запуск его в том же цикле выполнения, что и основной поток, сказался на производительности, хотя я смог немного повысить производительностьнаписав класс-оболочку и запустив все сетевые операции ввода-вывода в фоновом потоке.

9 голосов
/ 10 апреля 2012

Это решение будет работать, если и только если у вас нет блокировки работы в потоке 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];

Это позволит вам запускать сетевые операции, не беспокоясь о блокировках.

...