Подтвердить что ты не робот

Буферизация NSOutputStream используется как NSInputStream?

У меня есть этот потребительский класс, который принимает NSInputStream в качестве аргумента, который будет обрабатываться async, и я хочу выталкивать данные, которые поступают от класса-производителя, который требует, чтобы у него был NSOutputStream, предоставленный в качестве исходного источника. Теперь как я могу настроить буферный (или прозрачный) поток, который действует как выходной поток для производителя, и одновременно с NSInputStream для моего потребительского класса?

Я немного посмотрел на NSOutputStream + outputStreamToMemory и + outputStreamToBuffer: емкость: но на самом деле не понял, как использовать его как вход для NSInputSource.

У меня было некоторое представление о создании класса среднего класса, в котором хранится фактический буфер, а затем создается два подкласса (по одному для каждого NSInput/OutputStream), который содержит ссылку на этот класс буферизации и что эти подклассы делегируют большинство вызовов этот класс, например, методы подкласса вывода hasSpaceAvailable, write: maxLength:, и для ввода hasBytesAvailable, read: maxLength: и т.д.

Приветствуются любые советы о том, как подойти к этой ситуации. Благодарю.

4b9b3361

Ответ 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

Возможно, вы захотите рассмотреть подкласс NSInputStream и обернуть исходный поток в новом классе, который буферизирует и/или изменяет байты по мере их прохождения.

Основная причина, по которой я нашел это для подхода с привязанными сокетами, - это поддержка поиска. Файловые NSInputStreams используют свойство stream для поиска в файле, и я не мог легко организовать это без подкласса.

Проблема с этим подходом заключается в том, что кажется, что бесплатный мост не будет работать для вашего подкласса, но есть очень хорошая статья, которая также даст вам подкласс класса, чтобы начать, если вам это нужно:

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

У меня есть буферное решение, работающее с использованием обоих подходов. Хотя еще одна проблема, с которой я столкнулась с подклассовым подходом, заключается в том, что вам нужно позаботиться о том, чтобы отправлять события слушателям соответствующим образом - например, когда ваш исходный поток отправляет вам событие EOF, вы не передадут его вашему потребителю до тех пор, пока они не опустошат буфер - так что там есть какая-то ошибка.

Кроме того, вам может потребоваться убедиться, что клиенты выполняют чтение с основного цикла запуска (я работал с большой центральной отправкой) - потому что любое наблюдение за вами в вашем подклассе - в потоке источника - будет конфликтовать с потребителем в противном случае. Хотя вы, кажется, можете выбрать любой цикл выполнения для наблюдения за потоками, работает только основной.

В общем, я бы сказал, что нужно идти с парными потоками, если вам не нужно поддерживать поиск - или особенно не склонны к методу парных потоков.

Ответ 3

Вот уже реализованный класс, который делает именно то, что вы хотите

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