如果一个子类引用一个超级伊娃,合成一个不相关的属性失败

编辑:我只是注意到这个其他堆栈溢出问题要求很多相同的事情: 为什么一个子类@property没有相应的伊娃隐藏超类ivars?

这是一些有趣的行为,我无法在官方或非官方(博客,鸣叫,SO问题等)中findlogging。 我把它解释成它的本质,并在一个新的Xcode项目中进行了testing,但我无法解释它。

MyBaseClass有一个实例variables:

@interface MyBaseClass : NSObject { NSObject *fooInstanceVar; } @end 

MySubclass扩展了MyBaseClass,并声明了一个完全不相关的属性(也就是说,该属性不打算由实例variables支持):

 #import "MyBaseClass.h" @interface MySubclass : MyBaseClass { } @property (nonatomic, retain) NSObject *barProperty; @end 

如果MySubclass的实现合成属性,但实现访问器方法,一切都很好(没有编译器错误):

 #import "MySubclass.h" @implementation MySubclass - (NSObject*)barProperty { return [[NSObject alloc] init]; // pls ignore flagrant violation of memory rules. } - (void)setBarProperty:(NSObject *)obj { /* no-op */ } - (void)doSomethingWithProperty { NSArray *array = [NSArray arrayWithObjects:self.barProperty, fooInstanceVar, nil]; NSLog(@"%@", array); } @end 

但是,如果我删除属性访问器方法并将其replace为属性的synthesize声明,我得到一个编译器错误: 'fooInstanceVar' undeclared (first use in this function)

 #import "MySubclass.h" @implementation MySubclass @synthesize barProperty; - (void)doSomethingWithProperty { NSArray *array = [NSArray arrayWithObjects:self.barProperty, fooInstanceVar, nil]; NSLog(@"%@", array); } @end 

如果我删除了synthesize声明,或者如果我没有从MySubclass.m中引用fooInstanceVar实例variables,或者如果将所有接口和实现定义放在单个文件中,则此错误消失。 在GCC 4.2和GCC / LLVM编译设置中,这个错误似乎也会发生。

任何人都可以解释这里发生了什么?

正如在这个问题中回答: objective c xcode 4.0.2:子类不能访问超类variables“未在此范围内声明”

从文档:Apple Objective-C编程语言: http : //developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocDefiningClasses.html#//apple_ref/doc/uid/TP30001163- CH12-TPXREF125

实例variables可以在声明它的类中和在inheritance它的类中访问。 所有没有明确的scope指令的实例variables都有@protected作用域。

但是,公共实例variables可以在任何地方被访问,就好像它是C结构中的字段一样。 例如:

Worker * ceo = [[Worker alloc] init];

ceo-> boss = nil;

我有使用LLVM GCC 4.2的编译错误(对于iOS项目,在设备上):

错误:'fooInstanceVar'未声明(首次在此函数中使用)和使用GCC 4.2相同:错误:'fooInstanceVar'未声明(首次在此函数中使用)

我可以编译使用LLVM编译器2.0没有错误。

用LLVM GCC 4.2和GCC 4.2编译,使用自>:

[NSArray arrayWithObjects:self.barProperty,self-> fooInstanceVar,nil]; 在doSomethingWithProperty方法中。

编译器的行为是正确的。 在一个超类中使用存储的子类中的合成是不成文的。

在某些情况下,对llvm提出了一个错误。 它可能在可公开访问的错误数据库中。

无论如何,请提交一个错误,要求澄清这个特定的规则。


我只是试了一下,它没有任何警告地编译。 我没做什么?

 @interface MyBaseClass : NSObject { NSObject *fooInstanceVar; } @end @interface MySubclass : MyBaseClass { } @property (nonatomic, retain) NSObject *barProperty; @end @implementation MyBaseClass @end @implementation MySubclass @synthesize barProperty; - (void)doSomethingWithProperty { NSArray *array = [NSArray arrayWithObjects:self.barProperty, fooInstanceVar, nil]; NSLog(@"%@", array); } @end 

目前还不清楚你想要解决什么问题。 所有的实例variables都是非脆弱的,但是32位的Mac OS X.

我也不能重现你的错误。 你有一个非默认的编译器标志集? 你能提供你的项目的副本吗? 这绝对是编译器中的一个bug。

看看这篇文章是为了最好地利用@ property / @ synthesize。 一个简短的总结就是从你的对象中删除所有的ivars(除非你由于某种原因需要使用32位运行时)。 然后只使用你的getter和setter,而不是直接访问合成的ivars。 在此之后将避免以后的任何问题。