缓冲 NSOutputStream 用作 NSInputStream?

发布于 2024-09-09 02:58:52 字数 495 浏览 10 评论 0原文

我有一个消费者类,它采用 NSInputStream 作为参数,它将被异步处理,并且我想推送来自生产者类的数据,该生产者类要求它提供 NSOutputStream 作为其输出源。现在我如何设置一个缓冲(或透明)流作为生产者的输出流,同时作为我的消费者类的 NSInputStream ?

我稍微研究了一下 NSOutputStream +outputStreamToMemory 和 +outputStreamToBuffer:capacity: 但还没有真正弄清楚如何将其用作 NSInputSource 的输入。

我有一些想法,即设置一个保存实际缓冲区的中间人类,然后创建两个子类(每个 NSInput/OutputStream 一个),它保存对此缓冲类的引用,并让这些子类将大部分调用委托给该类,例如,输出子类方法 hasSpaceAvailable、write:maxLength:,对于输入,有 hasBytesAvailable、read:maxLength: 等。

任何有关如何处理这种情况的提示都值得赞赏。谢谢。

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 it has an NSOutputStream provided as its output source. Now how could I set up a buffering (or transparent) stream that acts as the output stream for the producer, and at the same time as the NSInputStream for my consumer class?

I've looked a bit at the NSOutputStream +outputStreamToMemory and +outputStreamToBuffer:capacity: but haven't really figured out how to use it as input for an NSInputSource.

I had some idea of setting up a middle-man class that holds the actual buffer, then creating two subclasses (one for each NSInput/OutputStream) which holds a reference to this buffering class, and having these subclasses delegate most calls to that class, e.g output subclass methods hasSpaceAvailable, write:maxLength:, and for the input, hasBytesAvailable, read:maxLength: etc.

Any tips on how to approach this situation are appreciated. Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

何以畏孤独 2024-09-16 02:58:52

实现此目的的一种方法是使用苹果开发人员网站上的示例代码。
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

基本上你将两个流的末端与一个缓冲区连接在一起。

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.

深爱成瘾 2024-09-16 02:58:52

您可能需要考虑子类化 NSInputStream,并将源流包装在新类中,该类在字节通过时缓冲和/或修改字节。

我发现通过绑定套接字方法执行此操作的主要原因是支持查找。基于文件的 NSInputStreams 使用流属性在文件中查找,如果没有子类化,我无法轻松安排它。

这种方法的一个问题是,免费桥接似乎不适用于您的子类 - 但有一篇非常好的文章,如果您需要一个模板子类,它还会为您提供一个模板子类:

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

我得到了一个使用这两种方法工作的缓冲解决方案 - 尽管我在使用子类方法时遇到的另一个问题是您需要注意适当地向侦听器发送事件 - 例如,当您的源流向您发送 EOF 事件时,您赢了在消费者清空缓冲区之前,不要将其传递给他们 - 所以那里会发生一些混乱。

另外 - 您可能需要确保客户端在主运行循环中进行读取(我让它与中央调度一起工作) - 因为您在子类中(在源流上)所做的任何观察都会与消费者发生冲突。尽管您似乎可以选择任何运行循环来观察流,但只有主循环可以工作。

因此,总的来说,我会说使用配对流,除非您需要支持查找 - 或者特别反对配对流方法。

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.

只为守护你 2024-09-16 02:58:52

这是一个已经实现的类,它完全可以实现您想要的

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

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];
自在安然 2024-09-16 02:58:52

任何仍在使用 Objecive C 的人,从 iOS 8 开始,这是规范的方法:

NSStream:getBoundStreamWithBufferSize:inputStream:outputStream:

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

NSStream:getBoundStreamWithBufferSize:inputStream:outputStream:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文