让我们考虑具有高度自定义或复杂视图的应用程序。
我们将有一种特定类型的视图控制器发送方法到特定类型的UIView,其中UIView本身由许多其他视图组成。
视图应该具有丰富的特定于域的界面,允许控制器在它和类似的丰富模型之间进行操作。
所以我们覆盖控制器的视图属性,如下所示:
@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对于定义另一个访问器是有意义的,我只需将消息发送到特定类型的UIView而无需强制转换。
问题:唯一的问题是它会导致编译器警告:
属性类型'PlaybackView *'与从'UIViewController'继承的类型'UIView *'
不兼容。 。我喜欢构建没有任何警告的代码。这样,有效的警告不会被埋没在其他警告之中。
问题:
答案 0 :(得分:7)
这里的问题不是覆盖属性,而是使用类类型的前向声明。
所以这......
@class PlaybackView;
@interface PlaybackViewController : UIViewController
@property (nonatomic, strong) PlaybackView* view;
@end
将为您提供上述警告,因为编译器无法知道PlaybackView
的继承层次结构。 UIViewController
签订合同,从UIView
媒体资源
view
它告诉你它认为PlaybackView
不是UIView
这里的简单解决方案是使用#import
代替编译器完全了解PlaybackView
...
#import "PlaybackView.h"
@interface PlaybackViewController : UIViewController
@property (nonatomic, strong) PlaybackView* view;
@end
另外(但由于PCH是优化功能并且不应管理依赖性,因此非常糟糕)是将#import "PlaybackView.h"
添加到您的项目PCH
答案 1 :(得分:1)
根据使用#import
而不是@class
的其他答案中的建议会清除警告,但建议尽可能少地导入标题中,因此我建议保留view
没有变化并且有一个额外的PlaybackView * playbackView
:
view
和playbackView
指向同一视图完全没问题。view
的类必须导入您的控制器标头,因此他们可以首先使用playbackView
。UIScrollView
超级视图),您将不必重构其他代码和类!答案 2 :(得分:0)
我认为覆盖UIViewControllers视图属性不是一个好方法。
我认为最好这样做:
@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
并在.m文件中。
- (void)loadView
{
PlaybackView *mainView = [[PlaybackView alloc] initWithFrame:[UIScreen mainScreen].applicationFrame];
// set the mainView
self.view = mainView;
}
你可以像这样使用你的PlaybackView。
((PlaybackView *)(self.view)).oscClient
或
((PlaybackView *)(xxxViewControler.view)).oscClient
答案 3 :(得分:0)
[UPDATE]
最后我可能找到了一个适合这个问题的解决方案:
这是一个快速而又脏的方法,只是为了抑制警告,尝试将代码包装在这些行之间
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
//YOUR CODE
#pragma clang diagnostic pop
或 - 墙 要了解有关编译器警告抑制的更多信息Clang Manual
[OLD ANSWER]
我想给我2美分。
如果我理解你正在尝试创建一种抽象工厂,它将为您提供基于视图控制器功能的视图的专用版本。在我看来,故事板在这种设计中效果不佳,但我想向你展示我对它的看法。
首先,我将为您的视图控制器创建一个抽象类,在接口中,您将在所有VC子库中声明所需的所有属性,例如:
PlaybackView类是一个类集群,例如NSNumber,你在其上调用一个工厂方法,它将返回一个可能因case而异的对象。如果你检查一个NSnumber,它会返回一个不同的对象,如果你创建一个浮点数或一个整数,但它们都是NSNumber的子类,NSNumber声明它的子类的所有属性,但它没有实现它们。
现在,您可以在抽象类的-viewDidLoad方法中执行的操作是调用类似的方法
PlaybackView *plbackView = [PlaybackView playbackViewFroProperty:self.playbackProperty];
[self.view addSubview:playbackView];
self.playbackView = plbackView;
可以在viewcontroller storyboard编辑器的 User defined runtime attibute
内对playbackProperty进行估值。
答案 4 :(得分:0)
在某种意义上,也许您可以声明另一种为您提供演员表的方法。
@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;
}
不完全是最干净的方法,但它确实避免了self.view
上的强制转换(尽管不使用self.view
)