0

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

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

viewDidLoad我的 viewController 中,我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;

该属性idrawRect在 myView 中使用;所以,从我的 viewController 我会这样设置:

self.myView.i = 100;

所以我的问题是:

为什么我可以[self.view setNeedsDisplay];在不需要调用的情况下调用我的视图控制器[self.myView setNeedsDisplay];并将drawRect在 myView 中调用,但我不能像self.view.i在我的视图控制器中self.myView已经分配的self.view那样viewDidLoad在我的视图控制器中进行操作?

4

3 回答 3

2

您可以调用[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做同样的事情:viewtableView属性都返回相同的视图实例,但属性的类型不同。

重要的是要记住,属性的类型不一定与其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
于 2014-01-30T20:45:03.583 回答
1

在我的 viewController 的 viewDidLoad 中,我像这样分配和初始化 self.myView:

self.myView = [[MyViewClass alloc] initWithFrame:(CGRect){{0, 0}, 320, 480}];
self.view = self.myView;

永远永远永远不会这样做viewDidLoadviewDidLoad表示你已经有了一个视图。你永远不应该改变你的视图控制器的视图。

设置您的视图很好(并且需要)loadView。这就是它的用途。但是在viewDidLoad,绝对不是。

于 2014-01-30T20:11:14.780 回答
0

您正在尝试用 UIView 子类替换 VCs 视图,它是否以所有常用方式工作,但也让 vc 的代码访问子类上的属性?我认为您可以通过覆盖视图获取器来实现:

- (MyView *)view {
    return (MyView *)[super view];
}

此外,您可以将 IB 中的自定义视图设置为 VC 的视图,因此无需在 loadView 中执行任何操作。

于 2014-01-30T20:23:51.083 回答