Buffering NSOutputStream used as NSInputStream?

前端 未结 4 908
花落未央
花落未央 2020-12-28 08:36

I have this consumer class that takes an NSInputStream as argument which will be processed async, and I want to push data that comes from a producer class that requires that

相关标签:
4条回答
  • 2020-12-28 08:52

    You might want to consider subclassing NSInputStream, and wrapping the source stream in your new class that buffers and/or modifies the bytes as they pass through.

    The main reason I found for doing this over the bound sockets approach is to support seeking. File based NSInputStreams use a stream property to seek within the file, and I couldn't easily arrange this without subclassing.

    A problem with this approach is that it seems toll-free bridging won't work for you subclass - but there is a very nice article that will also give you a template subclass to start from if you need one:

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

    I got a buffering solution working using both approaches - although another issue I had with the subclass approach is that you need to take care to send events to listeners appropriately - for example, when your source stream sends you an EOF event, you won't pass it on to your consumer until they have emptied the buffer - so there is some messing about to do there.

    Also - you might need to ensure that clients do their reading off the main run loop (I got it working with grand central dispatch) - because any observing you do in your subclass - on the source stream - will clash with the consumer otherwise. Although you appear to be able to pick any run loop to observe streams on, only the main one works.

    So overall I'd say go with the paired streams unless you need to support seeking - or are particularly averse to the paired streams method.

    0 讨论(0)
  • 2020-12-28 08:54

    One way to accomplish this would be to use the example code on the apple developer site. SimpleURLConnection example

    This is how to do it, as can be seen in the PostController.m code

    @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
    

    Basically you attach the ends of two streams together with a buffer.

    0 讨论(0)
  • 2020-12-28 09:13

    Anyone still using Objecive C, as of iOS 8 this is the canonical way to do it:

    NSStream:getBoundStreamWithBufferSize:inputStream:outputStream:

    0 讨论(0)
  • 2020-12-28 09:16

    Here is an already implemented class that does exactly what you want

    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];
    
    0 讨论(0)
提交回复
热议问题