5

長い間ウェブを検索していたのですが…答えが見つからなかったので、ここに投稿することにしました。NSStreamを使用してNNTPサーバーへの接続を確立しようとしています。

テストプログラムでは、ストリームを開いてメッセージを送信します。デリゲートメソッド(stream:handleEvent:)は、出力ストリーム(NSStreamEventOpenCompletedNSStreamEventHasSpaceAvailable)に対して2回呼び出されますが、入力ストリームに対しては呼び出されません

入力ストリームがデリゲートを呼び出さないのはなぜですか?何か案は?

基本的に、コードは次のようになります。

初期化およびオープンストリーム:

CFReadStreamRef tmpiStream;
CFWriteStreamRef tmpoStream;

CFStreamCreatePairWithSocketToHost(NULL, (__bridge CFStringRef)SERVER, PORT, &tmpiStream, &tmpoStream);

iStream = (__bridge NSInputStream *) tmpiStream;
oStream = (__bridge NSOutputStream *)tmpoStream;

[iStream setDelegate:self];
[oStream setDelegate:self];

[iStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[oStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];

[iStream open];
[oStream open];

メッセージを送る:

NSData *data = [[NSData alloc] initWithData:[messageString dataUsingEncoding:NSASCIIStringEncoding]];
[oStream write:[data bytes] maxLength:[data length]];

メッセージを受信する:

-(void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
    NSLog(@"EventCode: %i", eventCode);
    //switch-case-statement...(using constants - NSStreamEventOpenCompleted...)
}

そのコードを含むクラスはNSObjectsを継承し、を実装しNSStreamDelegateます。(iOS5とARC)

助けてくれてありがとう!

編集:私はこのようなストリームを開いた後に「ポーリング」を試みました-それは機能しています:

while (![iStream hasBytesAvailable])
{}
uint8_t buffer[1024];
int len;
NSString *str = @"";

while ([iStream hasBytesAvailable]) 
{
    len = [iStream read:buffer maxLength:sizeof(buffer)];
    if (len > 0) 
    {
        NSString *output = [[NSString alloc] initWithBytes:buffer length:len encoding:NSISOLatin1StringEncoding];

        if (output != nil) 
        {
            str = [str stringByAppendingString:output];
        }
    }
}
NSLog(@"Response: %@", str);

しかし、確かに、私はまだより良い(非同期)ソリューションが必要です;)

4

3 に答える 3

1

ここであなたの答えを見つけました、私は同じ問題を抱えています。あなたの答えは私にとってはうまくいきましたが、これはうまくいくと思います:

NSStream でデリゲートを使用するには?

彼を引用するには:

デリゲート メソッドを呼び出すのに十分な時間、実行ループが実行されていません。

追加:

[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:2.0]];

ストリームを開いた直後。これは、GUI を使用しないプログラムでのみ必要です。そうしないと、実行ループがスピンされてしまいます。

したがって、私の場合は次のようになります。

[self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.inputStream open];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:30.0]];

編集: 次に、データを取得したら、たとえば、デリゲート メソッド stream:handleEvent で NSStreamEventEndEncountered が発生したときにすべてのデータが完了しました。

[theStream removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
CFRunLoopStop(CFRunLoopGetCurrent());
[theStream close];

これは、30.0 秒より前に実行ループを閉じるか、設定した長さになります。コードが NSStreamHasBytesAvailable にある場合、答えは同じです。

これにより、引き続きデリゲート メソッドを使用して、デリゲート メソッドをすべてスキップすることなく、ダウンロードが完了するまで実行ループを開いたままにすることができます。

于 2014-10-04T20:29:33.253 に答える
0

実行ループをデフォルトモードで実行させていますか?

入力ストリームのステータスを確認してみてください(-streamStatus)。

コンソールに何かが記録されていますか?

デリゲートメソッドが出力ストリームに対して呼び出されたと主張しましたが、NSLog()呼び出しはストリームをログに記録しません。本気ですか?

最後に、これは無関係ですが__bridge_transfer、所有しているCore Foundationストリームオブジェクトの所有権をARCに譲渡する場合は、キャストを使用する必要があります。さらに良いCFBridgingRelease()ことに、関数名のCreateと明らかに対称であるため、を使用します。CFRelease()表示しなかった呼び出しがない限り、既存のコードはそれらのストリームをリークしています。

于 2012-06-04T23:00:53.880 に答える
0

私はこれと同じ問題を抱えていましたが、誤って電話をかけたことに気付きました

[iStream setDelegate:self]

iStream を作成する前に。

于 2014-11-06T05:23:44.507 に答える