You are able to call [self.view setNeedsDisplay]
, but not self.view.i
because UIViewController
's view
property is of type UIView
.
self.myView has been assigned to self.view already in viewDidLoad
Remember that the actual assignment happens at runtime, while compiler errors are generated at compile time. The compiler has no idea in what order your view controller's methods may be called, so it can't make any guesses about the actual type of a property's value beyond the property's original declaration. As far as Xcode is concerned, self.view
is just a UIView
.
As danh suggested above, you can override the property declaration to inform the compiler that your view is of type MyView
. Although, your approach of using the self.myView
property may be preferred anyway: it allows you to change up the view hierarchy in the future without changing your interface, and doesn't muck with inherited methods. UITableViewController
does the same thing: both the view
and tableView
properties return the same view instance, but the properties are typed differently.
It's important to remember that the type of a property is not necessarily the same as the type of its value. self.view
may have been assigned to an instance of MyView
, but the property is still of type UIView
. Regardless of the type of object assigned to it, the property's accessor is still a method with return type UIView
.
So, as far as the compiler is concerned, self.view
is nothing more than a plain old UIView
, even if you know that it isn't.
I think it would help to elaborate more on what properties are, and differentiate between the property and the instance. When you create a property like this:
@interface MyViewController : UIViewController
@property(strong, nonatomic) MyView *myView;
@end
The compiler translates it into a variable, an accessor method (the "getter"), and a mutator method (the "setter"). The property is merely shorthand for declaring the methods like so:
@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
When you call self.myView
, or self.view
, you are actually calling the accessor method; it's equivalent to [self myView]
or [self view]
. What it returns is a pointer to an object in memory. Because you assigned self.view = self.myView
, both properties are set to the same object; thus, both self.view
and self.myView
return a pointer to the same object.
To summarize:
- Assigning
self.view = self.myView
generates no compiler error, becauseMyView
is a subclass ofUIView
. Note that assigningself.myView = self.view
would generate a warning becauseUIView
is not a subclass ofMyView
- Calling
[self.view setNeedsDisplay]
causesmyView
to draw itself, because the same instance is assigned to both properties. If you log the descriptions (NSLog(@"view=%@, myView=%@", self.view, self.myView)
) for both properties, you can observe that they have the same memory address - You cannot call
self.view.i
because theview
property is declared to have typeUIView
, andUIView
has no method namedi
.