Создание и использование фиктивного подкласса NSData не работает

У меня возникла проблема с созданием собственного подкласса NSData, для которого я хочу иметь собственный метод description. Даже создание фиктивного подкласса NSData:

@interface MyData : NSData {}
@end

и

@implementation MyData
@end

и его использование приводит к странным ошибкам (функция, которая его использует, никогда не завершается, и управление каким-то образом возвращается в цикл выполнения). Я думал, что, возможно, я отвечаю за переписывание назначенных инициализаторов NSData (вызов реализации super), но ни один из них не упоминается в документе. Так:

  • каковы назначенные инициализаторы NSData?
  • какой минимум мне нужно написать для фиктивного подкласса NSData?

person F'x    schedule 24.04.2011    source источник


Ответы (2)


Создание подкласса NSData затруднено, потому что (как отмечено), он является членом кластер классов. Из Руководство по программированию двоичных данных:

... объекты данных не являются фактическими экземплярами классов NSData или NSMutableData, а вместо этого являются экземплярами одного из их частных подклассов.

Когда вы делаете [[NSData alloc] initWith...], вы не получаете обратно NSData; вы, вероятно, получите обратно NSConcreteData. Необыкновенный Cocoa With Love содержит обсуждение и демонстрацию кластеров подклассов .

Лучший (и наиболее идиоматический) вариант, вероятно, composition: ваш пользовательский класс должен просто содержать NSData ivar и реализовывать метод описания, который работает с этим вложенным объектом.

Хотя ответ Drawag технически правильный, это опасный метод для использования на классах Cocoa; он переопределит метод description каждого объекта NSData в программе, независимо от того, создаете вы его напрямую или нет.

В конкретном случае метода description это может быть нормально, но для другого метода, на который, скорее всего, будут полагаться другие объекты в фреймворке, это может вызвать большие проблемы, которые трудно отследить. Делать это следует только в том случае, если вы уверены, что другого пути нет.

Было бы намного лучше создать категорию и метод с префиксом:

@interface NSData (FX_Description) 
- (NSString *)FX_description;
@end

Документы Apple особо упомяните этот метод переопределения категорий и не советуйте его:

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

Если имя метода, объявленного в категории, совпадает с именем метода исходного класса или метода другой категории того же класса (или даже суперкласса), поведение не определено в отношении того, какая реализация метода используется в данный момент. время выполнения.

В более ранней версии документов говорилось:

Само присутствие некоторых методов категории может привести к изменению поведения во всех фреймворках. Например, если вы переопределяете метод делегата windowWillClose: в категории на NSObject, все оконные делегаты в вашей программе отвечают, используя метод категории; поведение всех ваших экземпляров NSWindow может измениться. Категории, которые вы добавляете в класс фреймворка, могут вызвать загадочные изменения в поведении и привести к сбоям. [Выделение мое.]

person jscs    schedule 24.04.2011

Если все, что вам нужно, это переопределить одну функцию «описание», рассмотрите возможность использования «Категории» вместо этого:

@interface NSData (MyData)
-(NSString*)description;
@end

@implimentation NSData (MyData)
-(NSString*)description
{
    return @"something";
}
@end

Затем вы можете использовать эту функцию в любом экземпляре NSData.

Очень сложно создать подкласс NSData, потому что это «кластер классов». Публичный API рассматривает его как один класс, но на самом деле это набор скрытых подклассов. Вы можете исследовать переопределение кластера классов, но это почти никогда не требуется. Другой вариант — создать класс «MyData» с NSData в качестве переменной-члена вместо использования подкласса.

person drewag    schedule 24.04.2011