编辑:我刚注意到其他Stack Overflow问题提出了同样的问题:Why does a subclass @property with no corresponding ivar hide superclass ivars?
这是一些有趣的行为,我无法在官方或非官方(博客,推文,SO问题等)中找到任何记录。我把它归结为它的本质,并在一个新的Xcode项目中进行了测试,但我无法解释它。
MyBaseClass有一个实例变量:
@interface MyBaseClass : NSObject {
NSObject *fooInstanceVar;
}
@end
MySubclass扩展了MyBaseClass,并声明了一个完全不相关的属性(也就是说,该属性不是由实例变量支持的):
#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
但是如果删除属性访问器方法并用属性的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
实例变量,或者我将所有接口和实现定义放入一个文件。 GCC 4.2和GCC / LLVM构建设置中似乎也会发生此错误。
有谁能解释这里发生了什么?
答案 0 :(得分:5)
在此问题中回答:objective c xcode 4.0.2: subclass can't access superclass variables "was not declared in this scope"
来自doc:Apple Objective-C编程语言: http://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocDefiningClasses.html#//apple_ref/doc/uid/TP30001163-CH12-TPXREF125
实例变量可以在声明它的类中以及在继承它的类中访问。没有显式范围指令的所有实例变量都具有@protected范围。
但是,可以在任何地方访问公共实例变量,就好像它是C结构中的字段一样。例如:
Worker * ceo = [[Worker alloc] init];
ceo-> boss = nil;
我使用LLVM GCC 4.2(对于iOS项目,在设备上)有编译错误:
错误:'fooInstanceVar'未声明(首次使用此功能) 和使用GCC 4.2的同一个: 错误:'fooInstanceVar'未声明(首次在此函数中使用)
我可以使用LLVM Compiler 2.0进行编译而不会出错。
使用自我>编译LLVM GCC 4.2和GCC 4.2。 :
[NSArray arrayWithObjects:self.barProperty,self-> fooInstanceVar,nil]; 在doSomethingWithProperty方法中。
答案 1 :(得分:0)
编译器表现正常;使用超类中的存储在子类中进行合成是禁止的。
在某些时候,有一个关于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
目前尚不清楚您要解决的问题。除了32位Mac OS X外,所有实例变量都是非脆弱的。
答案 2 :(得分:0)
我也无法重现你的错误。您是否设置了非默认编译器标志?你能提供一份项目副本吗?它似乎是编译器中的一个错误。
查看此article here以获得@ property / @ synthesize的最佳用途。快速摘要是从对象中删除所有ivars(除非您出于某种原因需要使用32位运行时)。然后只使用你的getter和setter,而不是直接访问合成的ivars。接下来将避免此bug的任何未来问题。