我正致力于构建iOS 6应用。
我有一个类 TDBeam ,它继承自超类 TDWeapon 。
超类 TDWeapon 在TDWeapon.h文件中声明@property:
@interface TDWeapon : UIView
@property (nonatomic) int damage;
@end
我没有明确地@synthesize属性,因为我让Xcode自动这样做。
在子类 TDBeam 中,我覆盖了TDBeam.m文件中的getter:
#import "TDBeam.h"
@implementation TDBeam
- (int)damage {
return _damage;
}
@end
Xcode按预期自动完成getter方法名称。但是当我尝试引用_damage实例变量(继承自超类)时,我得到一个编译器错误:
Use of undeclared identifier '_damage'
我在这里做错了什么?我已经尝试过明确地添加@synthesize,并更改_damage ivar的名称,但是编译器没有"看到"它或来自超类的任何其他ivars。我认为ivars是可见的,可以从子类访问?
答案 0 :(得分:21)
对于子类,合成的ivars 不是可见的,无论它们是显式创建还是自动创建:What is the visibility of @synthesized instance variables?由于它们在实现文件中有效声明,因此它们的声明不包含在“翻译单元“包括子类。
如果你真的想直接访问那个ivar,你必须在子类可以看到它的地方显式地声明它(在它的默认“受保护”形式),例如私有头中超类的类扩展
答案 1 :(得分:2)
Stack Overflow上有很多关于这个主题的帖子,其中没有一个提供简单的具体建议,但是这个主题最简洁地总结了一下,而Josh的回答是最好的。
如果这是你想要做的事情,那么他有点不会直截了当地告诉你,不要使用@property。如他所说,在你的基类中声明你的常规受保护变量,如果你需要,你可以写你自己的setter和getter。任何可以编写自己的setter / getters的子类都可以看到ivar。
至少那是我登陆这个问题的地方,虽然我对子类化有了全新的想法。
创建私有标头以托管您的匿名类别并在子类中重新合并您的ivars的想法在很多层面上似乎都是错误的。我也确定我可能错过了某个基本点。
修改
在一些失眠之后,受到Stanford's 2013 iTunes U course的启发,我相信这是解决这个问题的一个示例。
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,那么它们至少必须是公共只读属性(或者只是裸体的ivars)。
并不完全'过度消除吸气剂',但它实现了同样的事情,只需要一点思考。我很抱歉,如果试图让这个例子变得通用,那么优雅和清晰度已经失去了。