Objective-C выпускает свойство, объявленное в категории?

У меня есть категория в существующем классе, которая добавляет в класс свойство и несколько методов.

@interface AClass (ACategory) {
    NSString *aProperty;
}

@property (nonatomic, retain) NSString *aProperty;

@end

В файле реализации я хочу освободить это свойство, когда объект освобождается. Однако, если я объявлю dealloc в этом классе, насколько я понимаю, он переопределит сделку из исходного класса. Каков же правильный способ освободить этот aProperty, когда объект освобождается?

@implementation AClass (ACategory)

@synthesize aProperty;

- (void)dealloc {
    [aProperty release];
    // this will skip the original dealloc method from what I understand
    [super dealloc];
}

@end

person Anurag    schedule 06.12.2010    source источник


Ответы (2)


Ну, это немного проблематично, так как ваш код неверен.

  1. Вы не можете объявлять переменные экземпляра в категории; используя последнюю версию Objective-C ABI, вы можете объявлять новые переменные экземпляра в расширении класса (@interface AClass () {//...), но это отличается от категории (@interface AClass (ACategory)).
  2. Даже если бы вы могли, синтаксис объявления переменных экземпляра заключается в том, что они заключаются в фигурные скобки после строки @interface.

Вы можете объявить свойство в категории, но вам придется определить его хранилище без использования новой переменной экземпляра (следовательно, @dynamic вместо @synthesize).


Что касается вашего фактического вопроса, вы не можете вызвать исходную реализацию переопределенного метода, если вы не используете метод-swizzling (с помощью функций времени выполнения, таких как method_exchangeImplementations). Я рекомендую не делать этого в любом случае; это действительно страшно и опасно.


Обновление: объяснение переменных экземпляра в расширениях класса

Расширение класса похоже на категорию, но оно анонимно и должно быть помещено в файл .m, связанный с исходным классом. Это выглядит как:

@interface SomeClass () {
    // any extra instance variables you wish to add
}
@property (nonatomic, copy) NSString *aProperty;
@end

Его реализация должна находиться в основном блоке @implementation вашего класса. Таким образом:

@implementation SomeClass
// synthesize any properties from the original interface
@synthesize aProperty;
// this will synthesize an instance variable and accessors for aProperty,
// which was declared in the class extension.
- (void)dealloc {
    [aProperty release];
    // perform other memory management
    [super dealloc];
}
@end

Таким образом, расширение класса полезно для хранения частных переменных и методов экземпляра вне общедоступного интерфейса, но не поможет вам добавить переменные экземпляра в класс, который вы не контролируете. Нет проблем с переопределением -dealloc, потому что вы просто реализуете его, как обычно, включая все необходимое управление памятью для переменных экземпляра, которые вы ввели в расширение класса.

Обратите внимание, что этот материал работает только с последней 64-разрядной версией ABI Objective-C.

person Jonathan Sterling    schedule 06.12.2010
comment
+1 за метод swizzling ... действительно пугающий и опасный - person BoltClock; 06.12.2010
comment
спасибо @Jonathan .. Я смоделировал пример в редакторе SO, но спасибо за указание на синтаксическую ошибку. - person Anurag; 06.12.2010
comment
Если бы это было полезно, было бы здорово, если бы вы могли принять это как ответ на свой вопрос. В противном случае, дайте мне знать, если вас все еще что-то смущает, и я сделаю все возможное, чтобы прояснить это. :) - person Jonathan Sterling; 07.12.2010
comment
Не могли бы вы подробнее рассказать о том, как объявление переменной экземпляра будет работать с расширением класса? как бы мы позаботились о проблеме переопределения Dealloc? Спасибо :) - person Anurag; 07.12.2010

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

По сути, вы можете добавить связанный объект, как показано ниже:

static void* ASI_HTTP_REQUEST;  // declare inside the category @implementation but outside any method    

// And within a method, init perhaps
objc_setAssociatedObject(self, 
    &ASI_HTTP_REQUEST, 
    request, 
    OBJC_ASSOCIATION_RETAIN);

И освободите связанный объект, отправив 'nil':

// And release the associated object
objc_setAssociatedObject(self,
    &ASI_HTTP_REQUEST, 
    nil, 
    OBJC_ASSOCIATION_RETAIN);

Документация Apple находится здесь.

Мне потребовалось некоторое время, чтобы найти, поэтому я надеюсь, что это кому-то поможет.

person paulkmoore    schedule 14.04.2011
comment
Хорошо! Но последний вопрос: когда вы обнуляете связанный объект? Как узнать, что категория будет выпущена? - person David Hernandez; 08.08.2013