How do I override the “view” property in UIViewCon

2019-02-04 02:08发布

I have a custom UIViewController and custom UIView. I'd like to override the viewcontroller.view property to return MyCustomUIView.

Right now I have:

@interface MyViewController : UIViewController {    
    IBOutlet MyView* view;
}

@property (nonatomic, retain) IBOutlet MyView* view;

This compiles but I get a warning: property 'view' type does not match super class 'UIViewController' property type.

How do I alleviate this warning?

5条回答
劳资没心,怎么记你
2楼-- · 2019-02-04 02:42

The UIViewController's view property/method will return your view automatically. I think you'll just have to cast the result to MyView (or just use the id type):

MyView *myView = (MyView*)controller.view;
id myView = controller.view;

I think the code you have posted above will cause you trouble. You probably don't want to create a view member yourself (because then the controller will be storing 2 views, and might not use the right one internally) or override the view property (because UIViewController has special handling for it.) (See this question for more info about the latter.)

查看更多
在下西门庆
3楼-- · 2019-02-04 02:45

Sorry, but your short answer is wrong.

The correct implementation of this would be to add a @property to the header file with your return type. Then instead of @synthesize you add the getter and setter manually and return a cast type from [super view]

for instance my class is a PlayerViewController

PlayerViewController.h

@property (strong, nonatomic) IBOutlet PlayerView *view;

PlayerViewController.m

- (PlayerView *)view{
    return (PlayerView*)[super view];
}
- (void)setView:(PlayerView *)view{
    [super setView:view];
}

the important thing is to put the correct class into the view.

Putting a UIView where a PlayerView goes would likely work in the Interface Builder, but would not function correctly in the code.

I am currently using this implementation.

查看更多
We Are One
4楼-- · 2019-02-04 02:49

@lpaul7 already posted a link to Travis Jeffery's blog as a comment, but it's so much more correct than all the other answers that it really needs the code to be an answer:

ViewController.h:

@interface ViewController : UIViewController

@property (strong, nonatomic) UIScrollView *view;

@end

ViewController.m:

@implementation ViewController

@dynamic view;

- (void)loadView {
  self.view = [[UIScrollView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
}

@end

If you using a xib, instead of overriding loadView change the type of your view controller's root view and add IBOutlet to the property.

See Overriding UIViewController's View Property, Done Right for more details.

查看更多
太酷不给撩
5楼-- · 2019-02-04 02:51

If anyone is on Swift 2.0+, you can use protocol extensions for a reusable implementation:

// Classes conforming to this protocol...
protocol CustomViewProvider {

    typealias ViewType
}

// ... Will get customView accessor for free
extension CustomViewProvider where Self: UIViewController, Self.ViewType: UIView {

    var customView: Self.ViewType {
        return view as! Self.ViewType
    }
}


// Example:
extension HomeViewController: CustomViewProvider {
    typealias ViewType = HomeView
}

// Now, we can do something like
let customView: HomeView = HomeViewController().customView
查看更多
淡お忘
6楼-- · 2019-02-04 02:58

The short answer is that you don't. The reason is that properties are really just methods, and if you attempt to change the return type, you get this:

  • (UIView *)view;
  • (MyView *)view;

Objective-C does not allow return type covariance.

What you can do is add a new property "myView", and make it simply typecast the "view" property. This will alleviate typecasts throughout your code. Just assign your view subclass to the view property, and everything should work fine.

查看更多
登录 后发表回答