Objective-C:覆盖超类getter并尝试访问ivar时发生编译错误

我正在构build一个iOS 6应用程序。

我有一个inheritance自超类TDWeapon的TDBeam

超类TDWeapon在TDWeapon.h文件中声明@property:

@interface TDWeapon : UIView @property (nonatomic) int damage; @end 

我没有明确地@thenthesize属性,因为我让Xcode自动这样做。

TDBeam的子类中,我重写了TDBeam.m文件中的getter:

 #import "TDBeam.h" @implementation TDBeam - (int)damage { return _damage; } @end 

按照预期,Xcode会自动完成getter方法名称。 但是,当我试图引用_damage实例variables(从超类inheritance),我得到一个编译器错误:

 Use of undeclared identifier '_damage' 

我在这里做错了什么? 我已经试过显式添加@synthesize,并更改_damage伊娃的名称,但编译器不会“看到”它或超类的任何其他ivars。 我以为ivars是可见的,可以从子类访问?

合成的ivars对于子类是可见的,无论它们是显式还是自动创build的: @synthesized实例variables的可见性是什么? 由于它们在实现文件中被有效地声明,所以它们的声明不包括在包括该子类的“翻译单元”中。

如果你真的想直接访问这个ivar,你必须在子类可以看到的地方显式声明它(默认的“protected”forms),比如私有头文件中超类的类扩展。

在Stack Overflow这个主题上有很多post,其中没有一个提供简单的具体的build议,但是这个话题最简单的总结,Josh的答案是最好的。

他刚刚停止说的是,如果这是你想要做的事,根本不要使用@property。 按照他的说法,在你的基类中声明你的常规保护variables,如果你需要的话,写你自己的setter和getters。 任何可以编写自己的setter / getters的子类都可以看到ivar。

至less这是我在这个问题上的地方,虽然我总是newb来inheritance。

创build私有头文件来托pipe你的匿名类别和重新合并你的子类中的ivars的想法在许多层面上似乎是错误的。 我也确定我可能错过了某个基本点。


编辑

好吧,在睡眠不好之后,受到斯坦福大学2013年iTunes U课程的启发,我相信这是解决这个问题的一个例子。

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 

那么你只需要用你需要的任何定制逻辑来replace你的子类中的makeValueForNewMyProperty。 你的属性在基类中是“保护的”,但是你可以控制它的创build方式,这基本上是你在大多数情况下要实现的。

如果您的makeValueForNewMyProperty方法需要访问基类的其他ivars,那么它们至less必须是公共只读属性(或者仅仅是裸露的ivars)。

不是完全“消灭一个吸气剂”,而是通过一些想法达到同样的目的。 我很抱歉,如果试图使这个例子具有通用性,就会失去一些优雅和清晰。