Получать уведомления, когда объект NSData/CFData читается?

Я использую API, который принимает CFData объект, и мне нужно генерировать данные на лету, что является трудоемкой операцией. CFData читается потребителем случайным, несмежным образом, и на самом деле ему редко нужна вся длина данных - ему просто нужны определенные случайные фрагменты.

Я хотел бы улучшить производительность, только фактически генерируя биты, которые запрашивает потребитель, поскольку они запрашиваются.

Есть ли способ подкласса CFData/NSData чтобы я получал обратные вызовы при чтении фрагментов данных и генерировал их на лету?

Обновление: К сожалению, потребитель является сторонним кодом, и поэтому другие классы не являются опцией, если они каким-то образом магически не совместимы с CFData,

3 ответа

Решение

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

Что мы знаем о вашей ситуации

  1. Код клиента не может принимать другой тип / класс
  2. CFData является CoreFoundation C-type и не имеет времени выполнения для игры
  3. Клиент, вероятно, использует символы CoreFoundation для чтения этих данных.
    1. Если вам повезет, это через API-интерфейсы Foundation в Obj-C, который имеет время выполнения
  4. CFData оборачивает void * к данным, но в начале имеет некоторые отступы (вероятно, структуру), которые будет трудно имитировать, если вы попытаетесь создать CFData объект прокси

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

Возможно, вы хотите что-то более похожее NSInputStream:

NSInputStream является подклассом NSStream, который обеспечивает функциональность потока только для чтения.

NSInputStream является "бесплатным мостом" со своим аналогом Core Foundation, CFReadStreamRef. Для получения дополнительной информации о бесплатном мостовом соединении см. Бесплатное мостовое соединение.

Примечания по подклассам

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

CFDataRef а также NSData являются бесплатными мостами. Это означает, что вы можете пройти NSData экземпляр в коде, который ожидает CFData,

NSData это кластер классов. Это означает, что вы можете создать его подкласс и реализовать только примитивные методы и инициализаторы. За NSData Примитивные методы:

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

Вы также должны реализовать некоторые init... метод, который инициализирует ваш экземпляр.

Все остальные NSData функциональность предоставляется по категориям. Вы по-прежнему можете переопределить любой метод и предоставить собственную реализацию.

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

Тем не менее, вам нужно много удачи, чтобы реализовать то, что вы хотите. Но это может быть возможно.

В качестве примера я создал следующий манекен NSData подкласс:

@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 метод моего подкласса называется.

Другие вопросы по тегам