14 Stimmen

Puffernder NSOutputStream als NSInputStream verwendet?

Ich habe diese Verbraucherklasse, die einen NSInputStream als Argument nimmt, die async verarbeitet werden, und ich möchte Daten schieben, die von einer Producer-Klasse kommt, die erfordert, dass es einen NSOutputStream als seine Ausgabequelle bereitgestellt hat. Wie könnte ich nun einen puffernden (oder transparenten) Stream einrichten, der als Ausgabestream für den Produzenten und gleichzeitig als NSInputStream für meine Konsumentenklasse fungiert?

Ich habe mir den NSOutputStream +outputStreamToMemory und +outputStreamToBuffer:capacity: ein wenig angesehen, aber ich habe nicht wirklich herausgefunden, wie man ihn als Eingabe für eine NSInputSource verwenden kann.

Ich hatte einige Idee der Einrichtung einer Mittelmann-Klasse, die den tatsächlichen Puffer hält, dann erstellen zwei Unterklassen (eine für jede NSInput/OutputStream), die einen Verweis auf diese Pufferung Klasse hält, und mit diesen Unterklassen delegieren die meisten Aufrufe an diese Klasse, z.B. Ausgabe Unterklasse Methoden hasSpaceAvailable, write:maxLength:, und für die Eingabe, hasBytesAvailable, read:maxLength: usw.

Für jeden Tipp, wie man diese Situation angehen kann, bin ich dankbar. Danke!

11voto

JugsteR Punkte 1034

Eine Möglichkeit, dies zu erreichen, wäre die Verwendung des Beispielcodes auf der Apple Developer Site. SimpleURLConnection Beispiel

Wie im Code von PostController.m zu sehen ist, geht man folgendermaßen vor

@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

Im Grunde werden die Enden zweier Datenströme mit einem Puffer verbunden.

1voto

Adrian Bigland Punkte 1429

Sie könnten in Erwägung ziehen, NSInputStream zu unterklassifizieren und den Quellstrom in Ihre neue Klasse zu verpacken, die die Bytes beim Durchlaufen puffert und/oder modifiziert.

Der Hauptgrund, warum ich dies gegenüber dem Ansatz der gebundenen Steckdosen bevorzuge, ist die Unterstützung der Suche. Dateibasierte NSInputStreams verwenden eine Stream-Eigenschaft, um innerhalb der Datei zu suchen, und ich konnte dies nicht einfach arrangieren, ohne eine Subklasse zu erstellen.

Ein Problem bei diesem Ansatz ist, dass die gebührenfreie Überbrückung für Ihre Unterklasse nicht zu funktionieren scheint - aber es gibt einen sehr guten Artikel, der Ihnen auch eine Vorlage für eine Unterklasse gibt, mit der Sie beginnen können, falls Sie eine benötigen:

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

Ich habe eine Pufferlösung, die mit beiden Ansätzen funktioniert - obwohl ein weiteres Problem, das ich mit der Subklasse Ansatz hatte, ist, dass Sie darauf achten müssen, um Ereignisse an Hörer entsprechend zu senden - zum Beispiel, wenn Ihre Quelle Stream sendet Ihnen ein EOF-Ereignis, Sie werden es nicht auf Ihre Verbraucher weitergeben, bis sie den Puffer geleert haben - so gibt es einige Verwirrung über dort zu tun.

Außerdem müssen Sie möglicherweise sicherstellen, dass die Clients ihre Daten aus der Hauptlaufschleife lesen (ich habe es mit Grand Central Dispatch hinbekommen), da jede Beobachtung, die Sie in Ihrer Unterklasse - auf dem Quellstrom - durchführen, sonst mit dem Verbraucher kollidiert. Obwohl Sie in der Lage zu sein scheinen, jede Laufschleife zu wählen, um Streams zu beobachten, funktioniert nur die Hauptschleife.

Insgesamt würde ich also sagen, dass Sie sich für die gepaarten Ströme entscheiden sollten, es sei denn, Sie müssen die Suche unterstützen - oder Sie sind der Methode der gepaarten Ströme besonders abgeneigt.

0voto

Peter Lapisu Punkte 19050

Hier ist eine bereits implementierte Klasse, die genau das tut, was Sie wollen

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];

0voto

charshep Punkte 396

Jeder, der noch Objecive C verwendet, kann das ab iOS 8 auf diese Weise tun:

NSStream:getBoundStreamWithBufferSize:inputStream:outputStream:

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X