15

我正在构建一个 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 的名称,但编译器没有“看到”它或超类中的任何其他ivar。我认为 ivars 可以从子类中看到和访问?

4

2 回答 2

21

合成的 ivars 对子类可见,无论它们是显式创建的还是自动创建的:@synthesized 实例变量的可见性是什么?由于它们是在实现文件中有效声明的,因此它们的声明不包含在包含子类的“翻译单元”中。

如果您真的想直接访问该 ivar,则必须在子类可以看到它的某个地方显式声明它(以其默认的“受保护”形式),例如私有标头中超类的类扩展。

于 2012-10-28T22:02:25.770 回答
2

Stack Overflow 上有很多关于这个主题的帖子,没有一个提供简单的具体建议,但这个主题总结得最简洁,而 Josh 的回答是最好的。

他有点直截了当地说,如果这是你想做的事情,根本不要使用@property。正如他所说,在您的基类中声明您的常规受保护变量,并在需要时编写您自己的 setter 和 getter。任何可以编写自己的 setter/getter 的子类都可以看到 ivar。

至少那是我遇到的问题,尽管我对子类化完全是新手。

创建私有标头来托管您的匿名类别并在您的子类中重新@sythesizing 您的 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

然后,您只需将子类中的 makeValueForNewMyProperty 替换为您需要的任何自定义逻辑。您的属性在基类中受到“保护”,但您可以控制它的创建方式,这基本上是您在大多数情况下想要实现的目标。

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

不完全是“超越吸气剂”,但它实现了同样的事情,稍加思考。如果在尝试使示例通用的过程中丢失了一些优雅和清晰,我深表歉意。

于 2013-02-07T09:44:09.730 回答