Objective-C: ошибка компилятора при переопределении получателя суперкласса и попытка доступа к ivar
Я работаю над созданием приложения iOS 6.
У меня есть класс TDBeam, который наследуется от суперкласса TDWeapon.
Суперкласс TDWeapon объявляет @property в файле TDWeapon.h:
@interface TDWeapon : UIView
@property (nonatomic) int damage;
@end
Я не явно @synthesize свойство, поскольку я позволяю Xcode автоматически делать это.
В подклассе TDBeam я переопределяю getter в файле TDBeam.m:
#import "TDBeam.h"
@implementation TDBeam
- (int)damage {
return _damage;
}
@end
Xcode автоматически завершает имя метода getter, как и ожидалось. Но когда я пытаюсь ссылаться на переменную экземпляра _damage (унаследованную от суперкласса), я получаю ошибку компилятора:
Use of undeclared identifier '_damage'
Что я здесь делаю неправильно? Я попытался явно добавить @synthesize и изменить имя _damage ivar, но компилятор не "видит" его или любые другие ivars из суперкласса. Я думал, что ивары были видны и доступны из подклассов?
Ответы
Ответ 1
Синтезированные ivars не видны для подклассов, независимо от того, были ли они явно или автоматически созданы: Какова видимость переменных экземпляра @synthesized? Поскольку они эффективно объявлены в файл реализации, их декларация не включена в "блок переводов", который включает подкласс.
Если вы действительно хотите получить доступ к этому ivar напрямую, вам придется явно объявить его (в его защищенной форме по умолчанию) где-нибудь, что подкласс может его увидеть, например расширение класса суперкласса в закрытом заголовке.
Ответ 2
В Qaru много сообщений по этой теме, ни одна из которых не предлагает простых конкретных советов, но этот вопрос суммирует ее наиболее кратко, а ответ Josh - лучший в любом случае.
То, что он вроде бы перестает говорить прямо, есть, если это то, что вы хотите сделать, вообще не используйте @property. Объявите свою обычную защищенную переменную в своем базовом классе, как он говорит, и напишите, что вы являетесь собственными сеттерами и получателями, если они вам понадобятся. Ивар будет виден всем подклассам, которые затем могут писать свои собственные сеттеры/геттеры.
По крайней мере, когда я приземлился на проблему, хотя у меня был бы общий newb для подкласса.
Идея создания закрытых заголовков для размещения вашей анонимной категории и повторной фильтрации ваших ivars в вашем подклассе просто кажется неправильной на столь многих уровнях. Я также уверен, что я, вероятно, пропустил какой-то фундаментальный момент.
Изменить
Хорошо после некоторого потерянного сна, и вдохновленный курс iTunes UT в Stanford 2013, здесь я считаю, что это пример решения этой проблемы.
MYFoo.h
#import <Foundation/Foundation.h>
@interface MYFoo : NSObject
// Optional, depending on your class
@property (strong, nonatomic, readonly) NSString * myProperty;
- (NSString *)makeValueForNewMyProperty; //override this in your subclass
@end
MYFoo.m
#import "MYFoo.h"
@interface MYFoo ()
@property (strong, nonatomic, readwrite) NSString * myProperty;
@end
@implementation MYFoo
// Base class getter, generic
- (NSDateComponents *)myProperty {
if (!_myProperty) {
_myProperty = [self makeValueForNewMyProperty];
}
return _myProperty;
}
// Replace this method in your subclass with your logic on how to create a new myProperty
- (NSString *)makeValueForNewMyProperty {
// If this is an abstract base class, we'd return nil and/or throw an exception
NSString * newMyProperty = [[NSString alloc]init];
// Do stuff to make the property the way you need it...
return newMyProperty;
}
@end
Затем вы просто замените makeValueForNewMyProperty в своем подклассе на любую настраиваемую логику, в которой вы нуждаетесь. Ваша собственность "защищена" в базовом классе, но у вас есть контроль над тем, как она создается, и это в основном то, чего вы пытаетесь достичь в большинстве случаев.
Если ваш метод makeValueForNewMyProperty требует доступа к другим ivars базового класса, они, по крайней мере, должны быть общедоступными свойствами readonly (или просто голыми ivars).
Не совсем "избыточное избавление от геттера", но он достигает такого же уровня, с небольшой мыслью. Приношу свои извинения, если, пытаясь сделать пример родовым, теряется какая-то элегантность и ясность.