【问题标题】:How can I make a subclass of NSInputStream?如何创建 NSInputStream 的子类?
【发布时间】:2012-04-04 11:07:04
【问题描述】:

我想创建一个 NSInputStream 的子类。简单地说,我尝试像下面这样编写代码,

@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

而且,我使用的类如下。

SeekableInputStream *stm = [[SeekableInputStream alloc] initWithURL:url];

然后,在运行时,我可能会遇到以下错误消息。

-[SeekableInputStream initWithURL:]:无法识别的选择器发送到实例 0x10018ff30

我没有重写 initWithURL 来故意使用父母的方法。 据我所知,派生类可以使用父类的方法,不是吗?

不能继承像initWithURL这样的扩展方法吗?

有人告诉我如何对 NSInputStream 进行子类化吗?

【问题讨论】:

  • 您是否尝试(只是尝试)重新实现方法initWithURL
  • @Saphrosit 你的意思是“重新实现”为“覆盖”吗?如果是,我可以说是。我重写了 initWithURL 方法,但是,[super initWithURL] 调用失败,因为超级实例没有该方法。
  • 这可能是 NSInputStream 不知何故是“特殊的”,但我更强烈地怀疑你在某处搞砸了。例如,您并没有真正将那个版本的 H 文件包含在 M 文件中。
  • 为什么需要继承 NSInputStream?

标签: objective-c cocoa


【解决方案1】:

来自 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>

您需要导入类别。记住你不能子类化一个类别,只是覆盖它然后不能调用(或者如果可以,我不知道如何)

【讨论】:

  • CFStreamCreateBoundPair 应该比尝试继承 NSInputStream 并覆盖私有 API[1] 更安全。然而,AFNetworking 对此存在问题,因此不幸的是,私有 API 覆盖是目前最好的解决方案[2]。 [1]:osdir.com/ml/general/2012-02/msg08594.html [2]:github.com/AFNetworking/AFNetworking/pull/1044
  • @HeathBorders CFStreamCreateBoundPair 可能对解决其他问题有用,但不确定是否对 OPs 问题有用。恕我直言,AFNetworking 实现其子类的方式不仅是错误的,实现者也走在非常非常薄的冰上,特别是因为有一个实现没有问题并且不使用私有 API,Apple 可以拒绝任何时间。
  • 如果您阅读了我链接的线程,他们确实尝试过并遇到了错误。我同意他们应该坚持使用公共 API,但最终工作代码会胜出。
  • 我必须同意 Heath Borders 的观​​点。在我的情况下,使用 CFStreamCreateBoundPair 完美地替换了 NSInputStream 子类。我用它写 http 流到 NSURLConnection
  • @AlexeyKozhanov 你是如何使用它的?我昨天刚测试过,CFStreamCreateBoundPair 肯定坏了,如果你在 runloop 上安排流而不打开它,它会抱怨在没有打开的情况下发送事件。绑定对正在使用“你预定了吗?”作为发送事件的标准,而不是使用“你开门吗?”
【解决方案2】:

如果您在 SDK 中查看 NSStream.h,initWithURL 不是在核心类 NSInputStream 中定义的,而是在称为 NSInputStreamExtensions 的类别中定义的。我对从继承类调用基类类别中定义的方法了解不多,但这肯定是您遇到可见性问题的原因。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-28
    • 1970-01-01
    相关资源
    最近更新 更多