从 xcode 4.4 开始,您不需要 @synthesize
属性不再( see here ),编译器会为您完成。那么,为什么编译器会提示
use of the undeclared identifier _aVar
在我的
viewDidLoad
ViewControllerSubclass
的方法:@interface ViewController : UIViewController
@property (assign, nonatomic) int aVar;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.aVar = 5;
NSLog(@"Super value: %d", _aVar);
}
@end
@interface ViewControllerSubclass : ViewController
@end
@interface ViewControllerSubclass ()
@property (assign, nonatomic) int aVar;
@end
@implementation ViewControllerSubclass
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"Subclass value: %d", _aVar);
}
@end
如果我将所有内容都移动到一个文件而不是 4 个单独的文件用于各自的接口(interface)和实现,编译器反而会提示 _aVar
是私有(private)的。但是 _aVar 应该已经在我的 ViewControllerSubclass
中自动合成了。 .如果我将初始属性声明移至类扩展名,则仍将所有内容保存在 1 个文件中:
@interface ViewController ()
@property (assign, nonatomic) int aVar;
@end
构建仍然失败,说 _aVar
是私有(private)的。如果我回到 4 个文件设置,为相应的接口(interface)和实现 xcode 构建甚至没有警告。
如果我然后运行代码:
[[[ViewControllerSubclass alloc] init] view];
上述示例中的日志语句打印出以下内容:Super value: 0
Subclass value: 5
NSLog(@"Super value: %d", _aVar);
是有道理的产生 0
的结果因为这个变量应该是父类(super class)私有(private)的。但是,为什么 NSLog(@"Subclass value: %d", _aVar);
产生 5
的结果??这一切都很奇怪。
最佳答案
您混淆了几个不同的问题,当您谈论在文件之间跳转并且您没有指定错误发生的位置时,我有些困惑。
无论如何,存在实例变量可见性的问题。如果您在接口(interface)范围内声明您的 iVar,则默认情况下它们是 protected 。
@interface Foo : NSObject {
int protectedInt;
@private
int privateInt;
@public
int publicInt;
}
@end
当您合成 iVar 时,实例变量本身是私有(private)的,除非您明确指定它们。
方法将始终触发最派生的实现。
现在,当你调用这个...
[[[ViewControllerSubclass alloc] init] view];
您将分配一个子类、初始化并加载 View 。此代码将执行...
@implementation ViewControllerSubclass
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"Subclass value: %d", _aVar);
}
@end
它做的第一件事是调用基类实现......
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.aVar = 5;
NSLog(@"Super value: %d", _aVar);
}
@end
当然,它调用 super,但这部分在这里并不重要。下一行将 5 分配给 self.iVar。但是,哪个 iVar?它调用属性 setter 方法在这个物体上。这个实例是什么类型的?这是一个
ViewControllerSubclass
.由于您已为基类及其子类指定了相同的名称(并将该属性声明为类扩展的一部分),因此它们每个都有自己的私有(private)范围实例变量。但是,在最派生的实现上调用了一个方法。因此,self.iVar 将设置子类的实例变量。基类的实例变量保持不变。
当你
NSLog
该值,您正在访问未更改的基类的私有(private)实例变量。现在,在基类
viewDidLoad
之后完成后,我们为子类运行代码。它记录其私有(private)实例变量的值,该变量因基类调用属性 setter 而被更改。所以,它现在将打印它的值,即 5。
关于iphone - 在 xcode 4.4 中使用类扩展,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12130125/