12

ガイド「ソケットストリームの設定」に従い、クラスでそのコードを効果的に複製しました。デリゲートメソッドを何を試しても、呼び出されないようです。

私が持っているヘッダーファイルには(基本的に):

@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番目の目が私の間違いを見つけることができます。

忍耐強く、これまで読んでくれた人に感謝します!

4

2 に答える 2

29

このような行で:

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

使用する代わりに、[NSRunLoop currentRunLoop]に変更しました[NSRunLoop mainRunLoop]

編集2011-05-30:

これが機能しなかった理由は、を介してバックグラウンドスレッドでソケットを設定していたため+[NSThread detachNewThreadSelector:toTarget:withObject:]です。

そのようにすることで、新しい実行ループが作成されました。実行ループの開発者向けドキュメントを読んだ後、NSRunLoopに手動で実行するように指示する必要があることがわかりました。

メインスレッドと同じ実行ループで実行すると、パフォーマンスは問題ありませんでしたが、ラッパークラスを記述し、すべてのネットワークI / Oをバックグラウンドスレッドで実行することで、パフォーマンスを少し引き出すことができました。

于 2011-02-08T23:46:31.250 に答える
9

このソリューションは、スレッド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];

これにより、デッドロックを心配することなくネットワーク操作を実行できるようになります。

于 2012-04-10T17:51:54.523 に答える