Как я могу сделать подкласс NSInputStream?

Я хотел бы сделать подкласс NSInputStream. Просто я попытался закодировать, как показано ниже,

<code>@interface SeekableInputStream : NSInputStream
{
    NSUInteger startOffset;
    NSUInteger totalReadLen;
}

- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len;
- (BOOL)getBuffer:(uint8_t **)buffer length:(NSUInteger *)len;
- (BOOL)hasBytesAvailable;
- (void)open:(NSUInteger)offset;

@end
</code>

и я использовал класс следующим образом.

<code>SeekableInputStream *stm = [[SeekableInputStream alloc] initWithURL:url];
</code>

Затем во время выполнения я мог встретить следующее сообщение об ошибке.

-[SeekableInputStream initWithURL:]: unrecognized selector sent to instance 0x10018ff30

Я не переопределил initWithURL для преднамеренного использования родительского метода. Основываясь на моих знаниях, производный класс может использовать метод родительского класса, не так ли?

Нельзя ли наследовать такой метод расширения, как initWithURL?

Есть кто-нибудь, сообщите мне, как сделать подклассы NSInputStream?

 Hot Licks04 апр. 2012 г., 14:19
Может быть так, что NSInputStream является «особенным» как-то, но я более сильно подозреваю, что у вас где-то есть грязь. Например, вы на самом деле не включаете эту версию H-файла в M-файл.
 JeremyP04 апр. 2012 г., 15:44
Зачем вам нужен подкласс NSInputStream?
 Manlio04 апр. 2012 г., 13:47
Вы пытались (просто попытаться) на самом деле переопределить методinitWithURL?
 Kyokook Hwang04 апр. 2012 г., 14:01
@Saphrosit Вы имеете в виду «переопределение»? как "переопределить"? Если да, я могу сказать да. Я переопределил метод initWithURL, но вызов [super initWithURL] не удался, поскольку у суперэкземпляра нет метода.

Ответы на вопрос(2)

Если вы посмотрите NSStream.h в SDK,initWithURL определяется не в основном классеNSInputStream но в категории под названиемNSInputStreamExtensions, Я мало знаю о вызове методов, определенных в категории базового класса, из унаследованного класса, но это определенно может быть причиной проблемы видимости, с которой вы сталкиваетесь.

Решение Вопроса

От NSStream.h

// NSStream is an abstract class encapsulating the common API to NSInputStream and NSOutputStream.
// Subclassers of NSInputStream and NSOutputStream must also implement these methods.
@interface NSStream : NSObject
- (void)open;
- (void)close;

- (id <NSStreamDelegate>)delegate;
- (void)setDelegate:(id <NSStreamDelegate>)delegate;
 // By default, a stream is its own delegate, and subclassers of NSInputStream and NSOutputStream must maintain this contract. [someStream setDelegate:nil] must restore this behavior. As usual, delegates are not retained.

- (id)propertyForKey:(NSString *)key;
- (BOOL)setProperty:(id)property forKey:(NSString *)key;

- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode;
- (void)removeFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode;

- (NSStreamStatus)streamStatus;
- (NSError *)streamError;
@end

// NSInputStream is an abstract class representing the base functionality of a read stream.
// Subclassers are required to implement these methods.
@interface NSInputStream : NSStream
- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len;
// reads up to length bytes into the supplied buffer, which must be at least of size len. Returns the actual number of bytes read.

- (BOOL)getBuffer:(uint8_t **)buffer length:(NSUInteger *)len;
// returns in O(1) a pointer to the buffer in 'buffer' and by reference in 'len' how many bytes are available. This buffer is only valid until the next stream operation. Subclassers may return NO for this if it is not appropriate for the stream type. This may return NO if the buffer is not available.

- (BOOL)hasBytesAvailable;
// returns YES if the stream has bytes available or if it impossible to tell without actually doing the read.
@end

Как видите, функции initWithURL нет. Так что вашиsuper не работают, потому что это действительно не существует. Как говорит MrTJ, это класс категории. Это определено в:

// The NSInputStreamExtensions category contains additional initializers and convenience routines for dealing with NSInputStreams.
@interface NSInputStream (NSInputStreamExtensions)
- (id)initWithURL:(NSURL *)url NS_AVAILABLE(10_6, 4_0);

Итак, я думаю, что если вы используете его в своем подклассе, он может работать.

#import <Foundation/NSStream.h>

Вам необходимо импортировать категорию. Помните, что вы МОЖЕТЕ подклассифицировать категорию, просто перезаписать ее и потом не сможете позвонить (или, если сможете, я не знаю, как)

 30 авг. 2013 г., 19:09
@HeathBorders CFStreamCreateBoundPair может быть полезен при решении других проблем, но не уверен, полезен ли он для проблемы OP. И ИМХО, способ, которым AFNetworking реализует свой подкласс, не только неверен, разработчики также идут по очень, очень тонкому льду, тем более что существует реализация, которая работает без проблем и не использует частные API, от которых Apple может отказаться от любого время.
 28 апр. 2014 г., 18:38
Я должен согласиться с Хитом Бордерсом. В моем случае использование CFStreamCreateBoundPair отлично заменило подклассы NSInputStream. Я использовал его, чтобы записать поток http в NSURLConnection
 17 дек. 2015 г., 19:13
@AlexeyKozhanov Как ты это использовал? Я только что проверил вчера, и CFStreamCreateBoundPair определенно сломан, в том случае, если вы планируете поток на цикле выполнения без его открытия, он жалуется на отправку событий без открытия. Связанная пара использует «Вы запланированы?» в качестве критерия для отправки события вместо использования "Вы открыты?"
 30 авг. 2013 г., 16:42
Предполагается, что CFStreamCreateBoundPair безопаснее, чем пытаться создать подкласс NSInputStream и переопределить частные API [1]. Однако у AFNetworking были проблемы с этим, поэтому, к сожалению, частные переопределения API на данный момент являются лучшим решением [2]. [1]:osdir.com/ml/general/2012-02/msg08594.html [2]: github.com/AFNetworking/AFNetworking/pull/1044
 30 авг. 2013 г., 21:39
Если вы прочитали ветку, я связался, они попробовали это и столкнулись с ошибками. Я согласен, что они должны придерживаться общедоступных API, но в конечном итоге рабочий код выигрывает.

Ваш ответ на вопрос