Override UIViewController.view with a specific type

Consider an application with highly customizable or complex views.

We will have a certain kind of view manager methods for a specific type of UIView, where the UIView itself consists of several other views.

The view should have a rich, domain-specific interface that allows the controller to act - this is a thin layer of glue between it and a similarly rich model.

So, we will redefine our controller view property as follows:

@interface PlaybackViewController : UIViewController<StageLayoutDelegate, ControlPanelDelegate> { NSMutableArray* _sections; LightingMode _lightingMode; } @property (nonatomic, strong) PlaybackView* view; // <------ Specific type of view #pragma mark - injected @property (nonatomic, strong) id<OscClient> oscClient; @property (nonatomic, strong) AbstractStageLayoutView* stageLayoutView; @end 

Ovverriding makes sense in defining another accessor, and I can just send messages to a specific type of UIView without having to do it.

Problem: The only problem is that this leads to a compiler warning:

property type "PlaybackView" incompatible with type "UIView *" inherited from "UIViewController"

., and I like to create code that does not have any warnings. Thus, a valid warning is not missed, being buried among other warnings.

Question:

  • Is there a way to suppress this particular warning?
  • Why is this part of the default settings when most modern OO languages ​​gladly allow you to override a property or method in a subclass so that it returns a more specific subclass of the type declared in the superclass?
+4
source share
5 answers

The problem here is not in overriding the property, but in using a direct declaration of the type of the class.

So this is ...

 @class PlaybackView; @interface PlaybackViewController : UIViewController @property (nonatomic, strong) PlaybackView* view; @end 

will give you the specified warning because the compiler cannot know the inheritance hierarchy of the PlaybackView . UIViewController has a contract to provide a UIView from its view property

Telling you he thinks PlaybackView not a UIView

A simple solution here is to use #import instead to give the compiler full knowledge of PlaybackView ...

 #import "PlaybackView.h" @interface PlaybackViewController : UIViewController @property (nonatomic, strong) PlaybackView* view; @end 

an alternative (but very poor form, since PCH is an optimizing function and should not manage dependencies) is to add #import "PlaybackView.h" to your PCH projects

+7
source

As suggested in another answer using #import instead of @class , the warning will be removed, but it is recommended that you import it into the header as little as possible, so I would recommend leaving the view unchanged and having an additional PlaybackView * playbackView :

  • It’s great that both view and playbackView point to the same view.
  • Classes that need to have knowledge of your specialized view should import the title of your controller so that they can simply use playbackView in the first place.
  • More importantly, if you want to embed your custom view as a subtask in the future (which often happens with the addition of the UIScrollView supervisor), you don’t have to reorganize other code and classes!
  • It is a simple cleaner.
+1
source

I do not think that overriding the view property of UIViewControllers is a good way.

I think it’s better to do this:

 @interface PlaybackViewController : UIViewController<StageLayoutDelegate, ControlPanelDelegate> { NSMutableArray* _sections; LightingMode _lightingMode; } //@property (nonatomic, strong) PlaybackView* view; //you do not need this property #pragma mark - injected @property (nonatomic, strong) id<OscClient> oscClient; @property (nonatomic, strong) AbstractStageLayoutView* stageLayoutView; @end 

and in the .m file.

 - (void)loadView { PlaybackView *mainView = [[PlaybackView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame]; // set the mainView self.view = mainView; } 

and you can use your playbackview like this.

 ((PlaybackView *)(self.view)).oscClient 

or

 ((PlaybackView *)(xxxViewControler.view)).oscClient 
0
source

[UPDATE]
Finally, I probably found a solution that matches this problem: It's quick and dirty, just to suppress the warning, try wrapping your code between these lines

 #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wgnu" //YOUR CODE #pragma clang diagnostic pop 

or -Wall more about suppressing compiler warnings Clang Guide

[OLD ANSWER]
I would like to give 2 cents. If I understand well, you are trying to create a kind of abstract factory that gives you a specialized version of the view based on the functionality of the view manager. In my opinion, storyboards do not work very well in this design, but I would like to tell you about it.

First, I will create an abstract class for your view controller, where in the interface you declare all the property that you need in all your VC subcategories, for example:

  • OSClient
  • AbstractStageLayoutView
  • Playbackview as weak
  • playbackProperty

The PlaybackView class is a cluster of classes, such as NSNumber, you call the factory method on it, which returns an object that may differ from case to case. If you check NSnumber, it returns another object if you create a float or integer, but all of them are subclasses of NSNumber, and NSNumber declares all the properties of its subclasses, but does not implement them.
Now, what can you do in the -viewDidLoad method of an abstract class, a method like this is called

 PlaybackView *plbackView = [PlaybackView playbackViewFroProperty:self.playbackProperty]; [self.view addSubview:playbackView]; self.playbackView = plbackView; 

User defined runtime attibute can be evaluated inside the User defined runtime attibute in the viewcontroller storyboard editor.

0
source

Perhaps you could declare another method that provides you with a throw, in a sense.

 @implementation PlaybackViewController - (void)viewDidLoad { [super viewDidLoad]; // use view_ property instead of view self.view_.foo = 1; } - (void)loadView { CGRect frame = [UIScreen mainScreen].applicationFrame; self.view = [[PlaybackView alloc] initWithFrame:frame]; } - (PlaybackView *)view_ { return (PlaybackView *)self.view; } 

Not quite a clean approach, but it avoids casting to self.view (not using self.view , though)

0
source

All Articles