您可以调用[self.view setNeedsDisplay],但不能调用self.view.i,因为UIViewController 的view 属性属于UIView 类型。
self.myView 已在 viewDidLoad 中分配给 self.view
请记住,实际的赋值发生在运行时,而编译器错误是在编译时产生的。编译器不知道视图控制器方法的调用顺序,因此它无法猜测属性值的实际类型超出属性的原始声明。就 Xcode 而言,self.view 只是一个UIView。
正如上面 danh 建议的那样,您可以覆盖属性声明以通知编译器您的视图类型为 MyView。不过,无论如何,您使用 self.myView 属性的方法可能是首选:它允许您在将来更改视图层次结构而不更改您的界面,并且不会使用继承的方法。 UITableViewController 做同样的事情:view 和 tableView 属性都返回相同的视图实例,但属性的类型不同。
请务必记住,属性的类型不一定与其值的类型相同。 self.view 可能已分配给 MyView 的实例,但 属性 仍然是 UIView 类型。无论分配给它的对象类型如何,属性的访问器仍然是返回类型为UIView 的方法。
所以,就编译器而言,self.view 只不过是一个普通的旧 UIView,即使你知道它不是。
我认为这将有助于详细说明什么是属性,并区分属性和实例。当您创建这样的属性时:
@interface MyViewController : UIViewController
@property(strong, nonatomic) MyView *myView;
@end
编译器将它翻译成一个变量、一个访问器方法(“getter”)和一个修改器方法(“setter”)。该属性只是声明方法的简写,如下所示:
@interface MyViewController : UIViewController
{
MyView *_myView;
}
- (MyView *)myView; // accessor / getter
- (void)setMyView:(MyView *)myView; // mutator / setter
@end
@implementation MyViewController
- (MyView *)myView
{
return _myView;
}
- (void)setMyView:(MyView *)myView
{
_myView = myView;
}
@end
当你调用self.myView或self.view时,你实际上是在调用访问器方法;它相当于[self myView] 或[self view]。它返回的是一个指向内存中对象的指针。因为您分配了self.view = self.myView,所以两个属性都设置为同一个对象;因此,self.view 和 self.myView 都返回指向同一个对象的指针。
总结一下:
- 分配
self.view = self.myView 不会产生编译器错误,因为MyView 是UIView 的子类。请注意,分配self.myView = self.view 会 生成警告,因为UIView 不是MyView 的子类
- 调用
[self.view setNeedsDisplay] 会导致myView 绘制自己,因为相同的实例 被分配给这两个属性。如果您记录两个属性的描述 (NSLog(@"view=%@, myView=%@", self.view, self.myView)),您可以观察到它们具有相同的内存地址
- 您不能调用
self.view.i,因为view 属性已声明为UIView 类型,而UIView 没有名为i 的方法。