我有这个消费者类,它接受一个NSInputStream作为参数,它将被处理为异步,我想推送来自生产者类的数据,该生成器类要求它提供一个NSOutputStream作为其输出源。现在,我如何设置一个缓冲(或透明)流作为生产者的输出流,同时设置为我的消费者类的NSInputStream?
我看了一下NSOutputStream + outputStreamToMemory和+ outputStreamToBuffer:capacity:但是还没有真正弄清楚如何将它用作NSInputSource的输入。
我有一些想法设置一个包含实际缓冲区的中间类,然后创建两个子类(每个NSInput / OutputStream一个),它保存对此缓冲类的引用,并让这些子类委托大多数调用该类,例如输出子类方法hasSpaceAvailable,write:maxLength:,并且对于输入,hasBytesAvailable,读取:maxLength:etc。
有关如何处理这种情况的任何提示都表示赞赏。谢谢。
答案 0 :(得分:11)
实现此目的的一种方法是在Apple开发者网站上使用示例代码。 SimpleURLConnection example
这是如何做到的,如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
基本上你用缓冲区连接两个流的末端。
答案 1 :(得分:1)
您可能需要考虑子类化NSInputStream,并将源流包装在新类中,以便在通过时缓冲和/或修改字节。
我发现通过绑定套接字方法执行此操作的主要原因是支持搜索。基于文件的NSInputStreams使用stream属性在文件中进行搜索,如果没有子类化,我就无法轻松安排它。
这种方法的一个问题是,似乎免费桥接对你的子类不起作用 - 但有一篇非常好的文章,如果你需要的话,它还会给你一个模板子类:
http://bjhomer.blogspot.co.uk/2011/04/subclassing-nsinputstream.html
我使用这两种方法得到了一个缓冲解决方案 - 尽管我对子类方法的另一个问题是你需要注意将事件发送给听众 - 例如,当你的源流发送给你一个EOF事件时,你在他们清空缓冲区之前不会将它传递给你的消费者 - 所以那里有一些混乱。
另外 - 您可能需要确保客户端在主运行循环中读取它(我使用了大型中央调度) - 因为您在子类中执行的任何观察 - 在源流上 - 将与消费者冲突除此以外。虽然您似乎能够选择任何运行循环来观察流,但只有主流可以工作。
总的来说,除非你需要支持搜索 - 或者特别反对配对流方法,否则我会说配对流。
答案 2 :(得分: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];
答案 3 :(得分:0)
任何仍然使用Objecive C的人,从iOS 8开始,这是规范的方式:
NSStream:getBoundStreamWithBufferSize:inputStream:outputStream: