14

非同期に処理される引数として NSInputStream を取るこのコンシューマー クラスがあり、出力ソースとして提供される NSOutputStream を必要とするプロデューサー クラスからのデータをプッシュしたいと考えています。プロデューサーの出力ストリームとして機能し、同時にコンシューマー クラスの NSInputStream として機能するバッファリング (またはトランスペアレント) ストリームを設定するにはどうすればよいでしょうか?

NSOutputStream +outputStreamToMemory と +outputStreamToBuffer:capacity: を少し調べましたが、NSInputSource の入力として使用する方法がわかりませんでした。

実際のバッファを保持する仲介者クラスを設定し、このバッファリング クラスへの参照を保持する 2 つのサブクラス (NSInput/OutputStream ごとに 1 つ) を作成し、これらのサブクラスにほとんどの呼び出しをそのクラスに委譲させるという考えがありました。たとえば、出力サブクラス メソッドには hasSpaceAvailable、write:maxLength:、入力用には hasBytesAvailable、read:maxLength: などがあります。

この状況に対処する方法についてのヒントをいただければ幸いです。ありがとう。

4

4 に答える 4

11

これを実現する 1 つの方法は、Apple 開発者サイトのサンプル コードを使用することです。 SimpleURLConnection の例

PostController.m コードに見られるように、これはそれを行う方法です。

@interface NSStream (BoundPairAdditions)
+ (void)createBoundInputStream:(NSInputStream **)inputStreamPtr outputStream:(NSOutputStream **)outputStreamPtr bufferSize:(NSUInteger)bufferSize;
@end

@implementation NSStream (BoundPairAdditions)

+ (void)createBoundInputStream:(NSInputStream **)inputStreamPtr outputStream:(NSOutputStream **)outputStreamPtr bufferSize:(NSUInteger)bufferSize
{
    CFReadStreamRef     readStream;
    CFWriteStreamRef    writeStream;

    assert( (inputStreamPtr != NULL) || (outputStreamPtr != NULL) );

    readStream = NULL;
    writeStream = NULL;

    CFStreamCreateBoundPair(
        NULL, 
        ((inputStreamPtr  != nil) ? &readStream : NULL),
        ((outputStreamPtr != nil) ? &writeStream : NULL), 
        (CFIndex) bufferSize);

    if (inputStreamPtr != NULL) {
        *inputStreamPtr  = [NSMakeCollectable(readStream) autorelease];
    }
    if (outputStreamPtr != NULL) {
        *outputStreamPtr = [NSMakeCollectable(writeStream) autorelease];
    }
}
@end

基本的には、2 つのストリームの端をバッファーと一緒にアタッチします。

于 2011-12-06T14:43:43.753 に答える
1

NSInputStream のサブクラス化を検討し、ソース ストリームを新しいクラスにラップして、通過するバイトをバッファリングおよび/または変更することを検討してください。

バインドされたソケットのアプローチでこれを行う主な理由は、シークをサポートするためです。ファイル ベースの NSInputStreams は、ストリーム プロパティを使用してファイル内をシークします。

このアプローチの問題点は、無料のブリッジングがサブクラスに対して機能しないように見えることです - しかし、テンプレート サブクラスが必要な場合に開始するためのテンプレート サブクラスも提供する非常に優れた記事があります。

http://bjhomer.blogspot.co.uk/2011/04/subclassing-nsinputstream.html

両方のアプローチを使用して動作するバッファリング ソリューションを取得しました。ただし、サブクラス アプローチで発生した別の問題は、リスナーにイベントを適切に送信するように注意する必要があることです。たとえば、ソース ストリームが EOF イベントを送信した場合、消費者がバッファーを空にするまで、それを消費者に渡します。

また、クライアントがメインの実行ループから読み取りを行うようにする必要がある場合があります(グランドセントラルディスパッチで動作するようになりました)-サブクラスでソースストリームで行う観察は、そうでなければ消費者と衝突するためです。ストリームを監視するために任意の実行ループを選択できるように見えますが、機能するのはメインのループだけです。

したがって、シークをサポートする必要がない限り、またはペアストリーム方式を特に嫌う場合を除き、全体として、ペアストリームを使用することをお勧めします。

于 2012-03-19T10:41:23.507 に答える
0

これは、まさにあなたが望むことを行うすでに実装されたクラスです

BufferOutputStreamToInputStream

// initialize
self.bufferWriter = [[BufferOutputStreamToInputStream alloc] init];
[self.bufferWriter openOutputStream];

// later you want to set the delegate of the inputStream and shedule it in runloop
// remember, you are responsible for the inputStream, the outputStream is taken care off;)
self.bufferWriter.inputStream.delegate = self;
[self.bufferWriter.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
[self.bufferWriter.inputStream open]

// fill with data when desired on some event      
[self.bufferWriter addDataToBuffer:someData];
于 2015-02-04T10:01:46.970 に答える