我似乎已经忘记了这方面的基础知识,或者我太累了。
我有一个视图控制器和一个视图,它是UIView
的一个子类,名为MyViewClass。
在我的viewController的viewDidLoad
我alloc
和init
self.myView
这样:
self.myView = [[MyViewClass alloc] initWithFrame:(CGRect){{0, 0}, 320, 480}];
self.view = self.myView;
在我的viewController中,我会调用[self.view setNeedsDisplay];
。这里没问题。
我在MyViewClass.h中公开了一个属性:
@property(nonatomic) i;
属性i
将在myView中的drawRect
中使用;
所以,从我的viewController我会这样设置:
self.myView.i = 100;
所以我的问题是:
为什么我可以在我的视图控制器中调用[self.view setNeedsDisplay];
而无需致电[self.myView setNeedsDisplay];
,而drawRect
将在myView中调用,但我不能{{1}在我的视图控制器中self.view.i
已分配给我的视图控制器中self.myView
中的self.view
?
答案 0 :(得分:2)
您可以拨打[self.view setNeedsDisplay]
,但不能self.view.i
,因为UIViewController
的{{1}}属性属于view
类型。
self.myView已经在viewDidLoad
中分配给self.view
请记住,实际的赋值在运行时发生,而编译器错误是在编译时生成的。编译器不知道可以调用视图控制器的方法的顺序,因此它不能对属性的原始声明之外的属性值的实际类型进行任何猜测。就Xcode而言,UIView
只是self.view
。
正如上面提到的danh,您可以覆盖属性声明以通知编译器您的视图类型为UIView
。尽管如此,您使用MyView
属性的方法可能是首选的:它允许您在不更改界面的情况下更改视图层次结构,并且不会使用继承的方法。 self.myView
执行相同的操作:UITableViewController
和view
属性都返回相同的视图实例,但属性的输入方式不同。
重要的是要记住属性的类型不一定与其值的类型相同。 tableView
可能已分配给self.view
的实例,但属性仍为MyView
类型。无论分配给它的对象类型如何,属性的访问器仍然是返回类型为UIView
的方法。
因此,就编译器而言,UIView
只不过是一个普通的self.view
,即使你知道它不是。{/ p>
我认为有助于详细说明属性是什么,并区分属性和实例。当您创建这样的属性时:
UIView
编译器将其转换为变量,访问器方法(“getter”)和mutator方法(“setter”)。该属性仅仅是用于声明方法的简写:
@interface MyViewController : UIViewController
@property(strong, nonatomic) MyView *myView;
@end
当您致电@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
的方法。答案 1 :(得分:1)
在viewController的viewDidLoad中我像这样分配和初始化self.myView:
self.myView = [[MyViewClass alloc] initWithFrame:(CGRect){{0, 0}, 320, 480}];
self.view = self.myView;
永远不要永远不要在viewDidLoad
中这样做。 viewDidLoad
表示您已有视图。您永远不应该更改视图控制器的视图。
设置视图loadView
很好(也是必需的)。这就是它的用途。但在viewDidLoad
中,绝对不是。
答案 2 :(得分:0)
你试图用UIView子类替换VCs视图,让它以所有常用方式工作,还让vc的代码访问子类的属性?我认为你可以通过覆盖视图getter来实现目标:
- (MyView *)view {
return (MyView *)[super view];
}
此外,您可以在IB中将自定义视图设置为VC的视图,因此无需在loadView中执行任何操作。