在读取 NSData/CFData 对象时收到通知?

Get notifications when an NSData/CFData object is being read?

我正在使用带有 CFData 对象的 API,我需要动态生成数据,这是一项耗时的操作。 CFData 由消费者以随机、非连续的方式读取,它实际上很少需要数据的整个长度——它只需要其中的某些随机片段。

我想通过只实际生成消费者请求的位来提高性能。

有什么方法可以对 CFData/NSData 进行子类化,以便在读取数据块时获得回调并即时生成它们?

更新: 不幸的是,消费者是第 3 方代码,因此其他 类 不是一个选项,除非它们以某种方式神奇地与 [=11= 兼容].

也许您想要更像 NSInputStream:

NSInputStream is a subclass of NSStream that provides read-only stream functionality.

NSInputStream is “toll-free bridged” with its Core Foundation counterpart, CFReadStreamRef. For more information on toll-free bridging, see Toll-Free Bridging.

Subclassing Notes

NSInputStream is an abstract superclass of a class cluster consisting of concrete subclasses of NSStream that provide standard read-only access to stream data. Although NSInputStream is probably sufficient for most situations requiring access to stream data, you can create a subclass of NSInputStream if you want more specialized behavior (for example, you want to record statistics on the data in a stream).

我认为您不会喜欢这里的答案。您似乎在选项方面走投无路。

我们对您情况的了解

  1. 客户的代码不能接受不同的类型/class
  2. CFData 是 CoreFoundation C 类型,没有可运行的运行时
  3. 客户端可能使用 CoreFoundation 符号来读取此数据
    1. 如果幸运的话,它是通过具有运行时的 Obj-C 中的 Foundation APIs
  4. CFDatavoid * 包装到数据中,但在开头有一些填充(可能是结构),如果您尝试创建 CFData 将很难模仿代理对象

如果没有一些聪明的、不可维护的、整体危险的符号黑客技术,我将很难完成你想要的,我什至懒得去研究。

CFDataRefNSData 是免费桥接。这意味着,您可以将 NSData 实例传递给期望 CFData.

的代码

NSData 是一个 class 集群。这意味着,您可以 subclass 它,并且只实现原始方法和初始化器。 NSData 原始方法是:

@property (readonly) NSUInteger length;
@property (readonly) const void *bytes NS_RETURNS_INNER_POINTER;

您还必须实施一些 init... 方法,这将初始化您的实例。

所有其他 NSData 功能均按类别提供。您仍然可以覆盖任何方法并提供您自己的实现。

作为一个选项,您可以从 NSData subclass 开始,它将任何方法委托给内部 NSData 实例,您可以将其存储在 属性 中。通过这种方式,您可以观察第 3 方代码行为并调查您需要覆盖哪些方法。

不过,你需要很多运气才能实现你想要的。但有可能。

例如,我创建了以下虚拟 NSData subclass:

@interface MyData : NSData
@property (nonatomic, strong) NSData *innerData;
@end

@implementation MyData

- (id)initWithData:(NSData *)data {
    if (self = [super init]) {
        _innerData = data;
    }
    return self;
}

- (NSUInteger)length {
    NSLog(@"%@", NSStringFromSelector(_cmd));
    return self.innerData.length;
}

- (const void *)bytes {
    NSLog(@"%@", NSStringFromSelector(_cmd));
    return self.innerData.bytes;
}

@end

当我调用以下代码时:

NSData *originalData = [NSData dataWithBytes:"hello" length:5];
MyData *myData = [[MyData alloc] initWithData:originalData];
NSLog(@"%ld", CFDataGetLength((CFDataRef)myData));

length 调用了我的子方法class。