1

我正在尝试编写 NSOutputStream 的子类来执行一个非常简单的功能 - 跟踪发送到流的字节总数。但是,我在初始化函数实例时遇到了意外问题。这是代码:

#import <Foundation/Foundation.h>

@interface TrackingOutputStream : NSOutputStream {
  unsigned long long bytesWritten;
}

@property (readonly) unsigned long long bytesWritten;

@end

---------------------------

#import "TrackingOutputStream.h"

@implementation TrackingOutputStream
@synthesize bytesWritten;

- (NSInteger)write:(const uint8_t *)buffer maxLength:(NSUInteger)length {
  NSInteger written = [super write:buffer maxLength:length];
  bytesWritten += written;
  return written;
}

@end

但是,当我尝试初始化此类时:

TrackingOutputStream *os = [[[TrackingOutputStream alloc] initToFileAtPath:@"/tmp/test" append:NO] autorelease];

我收到以下错误:

-[TrackingOutputStream initToFileAtPath:append:]: unrecognized selector sent to instance 0x101a187e0

我尝试向调用 super 的类添加一个显式构造函数,但它没有任何区别(因为它不应该)。

4

3 回答 3

2

如果您正在使用一个需要 NSOutputStream 实例的 API,那么实现 NSOutputStream 的所有方法以便将它们转发到包装(委托)实例可能会很麻烦。您可以使用方法转发方法,该方法允许您在不编写所有包装方法的情况下添加行为。这涉及编写一个简单的实现forwardingTargetForSelector:respondsToSelector:


- (id)forwardingTargetForSelector:(SEL)aSelector {
    if (class_respondsToSelector([self class], aSelector)) { return self; }
    if ([self.delegate respondsToSelector:aSelector]) { return self.delegate; }
    return [super forwardingTargetForSelector:aSelector];
}

- (BOOL)respondsToSelector:(SEL)aSelector {
    if (class_respondsToSelector([self class], aSelector)) { return YES; }
    if ([self.delegate respondsToSelector:aSelector]) { return YES; }
    return [super respondsToSelector:aSelector];
}

有关更长、更详细的描述,请参阅有关使用Objective-C 鸭子类型更轻松地继承 NSOutputStream的博客文章。或查看https://github.com/jwb/ObjC-DuckType上的示例

于 2013-12-03T20:57:50.897 回答
1

NSOutputStream具有非常具体的子类化要求,记录在类的文档中。

请注意,文档明确指出您必须完全实现适当的初始化程序。即你不能子类来改变你描述的行为。至少,不容易。

相反,创建一个类,其实例包装一个实例NSOutputStream并添加您想要的行为。

于 2012-07-13T04:08:21.127 回答
0

作为附加说明,应该可以使用- propertyForKey:of检索有关书面数据的信息NSStream。查看 NSStreamDataWrittenToMemoryStreamKey属性键。

于 2015-04-14T17:26:59.560 回答