iOS:[self.view setNeedsDisplay];

时间:2014-01-30 20:08:23

标签: ios objective-c setneedsdisplay uiview-hierarchy

我似乎已经忘记了这方面的基础知识,或者我太累了。

我有一个视图控制器和一个视图,它是UIView的一个子类,名为MyViewClass。

在我的viewController的viewDidLoadallocinit 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

3 个答案:

答案 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执行相同的操作:UITableViewControllerview属性都返回相同的视图实例,但属性的输入方式不同。

重要的是要记住属性的类型不一定与其的类型相同。 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.myViewself.view都返回指向同一对象的指针。

总结:

  • 分配self.myView不会产生编译器错误,因为self.view = self.myViewMyView的子类。请注意,分配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中执行任何操作。