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

时间:2012-10-28 21:52:02

标签: objective-c ios properties instance-variables

我正致力于构建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是可见的,可以从子类访问?

2 个答案:

答案 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)。

并不完全'过度消除吸气剂',但它实现了同样的事情,只需要一点思考。我很抱歉,如果试图让这个例子变得通用,那么优雅和清晰度已经失去了。