您可以调用[self.view setNeedsDisplay]
,但不是self.view.i
因为UIViewController
'view
属性是 type UIView
。
self.myView 已在 viewDidLoad 中分配给 self.view
请记住,实际分配发生在运行时,而编译器错误是在编译时生成的。编译器不知道视图控制器方法的调用顺序,因此它无法猜测属性值的实际类型超出属性的原始声明。就 Xcode 而言,self.view
它只是一个UIView
.
正如上面 danh 建议的那样,您可以覆盖属性声明以通知编译器您的视图是 type MyView
。虽然,您使用该self.myView
属性的方法可能是首选:它允许您在将来更改视图层次结构而不更改您的界面,并且不会使用继承的方法。UITableViewController
做同样的事情:view
和tableView
属性都返回相同的视图实例,但属性的类型不同。
重要的是要记住,属性的类型不一定与其value的类型相同。self.view
可能已分配给 的实例MyView
,但该属性仍为 类型UIView
。无论分配给它的对象类型如何,属性的访问器仍然是一个返回类型的方法UIView
。
因此,就编译器而言,self.view
它只不过是一个普通的 old UIView
,即使你知道它不是。
我认为这将有助于详细说明什么是属性,并区分属性和实例。当您创建这样的属性时:
@interface MyViewController : UIViewController
@property(strong, nonatomic) MyView *myView;
@end
编译器将其转换为变量、访问器方法(“getter”)和 mutator 方法(“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
, orself.view
时,您实际上是在调用访问器方法;它相当于[self myView]
or [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
属性被声明为具有 type UIView
,并且UIView
没有名为 的方法i
。