Rem*_*ver 1 iphone ios xcode4.4
由于xcode 4.4你不再需要@synthesize属性了(见这里),编译器会为你做.那么,为什么编译器会抱怨
使用未声明的标识符_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
Run Code Online (Sandbox Code Playgroud)
如果我将所有内容移动到一个文件而不是相应的接口和实现的4个单独文件,则编译器会抱怨它_aVar是私有的.但_aVar应该已经自动合成了我的ViewControllerSubclass.
如果我将初始属性声明移动到类扩展,仍将所有内容保存在1个文件中:
@interface ViewController ()
@property (assign, nonatomic) int aVar;
@end
Run Code Online (Sandbox Code Playgroud)
构建仍然失败,说这_aVar是私有的.
如果我回到相应接口的4文件设置和实现xcode构建甚至没有警告.
如果我然后运行代码:
[[[ViewControllerSubclass alloc] init] view];
Run Code Online (Sandbox Code Playgroud)
上面示例中的日志语句打印出以下内容:
超值:0
子类值:5
因为这个变量应该是超类私有的NSLog(@"Super value: %d", _aVar);,0所以产生结果是有意义的.但是,为什么会NSLog(@"Subclass value: %d", _aVar);产生结果5?
这一切都很奇怪.
你混淆了几个不同的问题,当你谈到在文件之间跳转而你没有指定错误发生的位置时,我有点困惑.
无论如何,存在实例变量可见性的问题.如果在界面范围内声明iVar,则默认情况下它们受到保护.
@interface Foo : NSObject {
int protectedInt;
@private
int privateInt;
@public
int publicInt;
}
@end
Run Code Online (Sandbox Code Playgroud)
合成iVars时,实例变量本身是私有的,除非您明确指定它们.
方法将始终触发最派生的实现.
现在,当你打电话给这个......
[[[ViewControllerSubclass alloc] init] view];
Run Code Online (Sandbox Code Playgroud)
您将分配子类,初始化并导致加载视图.这段代码将执行...
@implementation ViewControllerSubclass
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(@"Subclass value: %d", _aVar);
}
@end
Run Code Online (Sandbox Code Playgroud)
它做的第一件事就是调用基类实现......
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.aVar = 5;
NSLog(@"Super value: %d", _aVar);
}
@end
Run Code Online (Sandbox Code Playgroud)
当然,它称之为超级,但这部分并不重要.下一行为self.iVar分配5.但是,哪个iVar?它在此对象上调用属性setter 方法.这个实例是什么类型的?这是一个ViewControllerSubclass.由于您已经为您的基类和它的子类赋予了相同的名称(并将该属性声明为类扩展的一部分),因此它们每个都有自己的私有范围实例变量.
但是,在最派生的实现上调用方法.因此,self.iVar将设置子类的实例变量.基类的实例变量保持不变.
当您使用NSLog该值时,您将访问基类的私有实例变量,该变量尚未更改.
现在,在基类viewDidLoad完成后,我们将获得为子类运行的代码.它记录其私有实例变量的值,该变量由于调用属性setter的基类而更改.因此,它现在将打印它的值,即5.
当您将超类声明设为public时,编译器将不会尝试重新合成该属性; 它假设已经在超类中得到了解决.因此,_aVar不在子类中的任何位置.无论如何它都是私有的,所以即使你把它们全部放在同一个文件中,也就是你看到这些错误的原因.
但是,当您在类扩展中创建超类属性声明时,编译器将自动合成超类和子类的属性.这最终导致两个类都具有私有实例变量_aVar(具有两个不同的地址).但是,当超类viewDidLoad方法设置属性时,该方法调用子类的访问器,这些访问器设置子类的private _aVar变量的值,而不是超类的值.这就解释了为什么你看到超类值没有改变.
希望这可以帮助!
| 归档时间: |
|
| 查看次数: |
691 次 |
| 最近记录: |