Создание и использование фиктивного подкласса NSData не работает - PullRequest
3 голосов
/ 24 апреля 2011

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

@interface MyData : NSData {}
@end

и

@implementation MyData
@end

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

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

Ответы [ 2 ]

10 голосов
/ 24 апреля 2011

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

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

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

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

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

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

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

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

Документы Apple специально упоминают эту технику переопределения категории и советуют:

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

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

Более ранняя версия документации продолжала говорить:

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

2 голосов
/ 24 апреля 2011

Если все, что вам нужно, это переопределить одну функцию "description", попробуйте вместо этого использовать "Category":

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

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

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

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

...