Swift:继承 UIViewController 的根视图
Posted
技术标签:
【中文标题】Swift:继承 UIViewController 的根视图【英文标题】:Swift: Subclassing a UIViewController's root view 【发布时间】:2014-06-10 01:47:56 【问题描述】:tl;dr:我如何告诉 Swift 我正在用 UIView
的子类覆盖 MyViewController
的 view
属性?
我想做的事
我非常喜欢为UIViewController
的视图提供UIView
的子类。例如:
// MyView --------------------------------------------------------
@interface MyView: UIView
@property (nonatomic, strong) UITableView *tableView;
@end
@implementation MyView
- (instancetype)initWithFrame:(CGRect)frame
if (self = [super initWithFrame:frame])
_tableView = [[UITableView alloc] initWithFrame:frame];
return self;
@end
// MyViewController ----------------------------------------------
@interface MyViewController: UIViewController <UITableViewDataSource>
@property (nonatomic, retain) MyView *view;
@end
@implementation MyViewController
- (void)loadView
self.view = [[MyView alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
- (void)viewDidLoad
[super viewDidLoad];
self.view.tableView.dataSource = self;
// etc.
@end
这很棒,因为它将视图创建和布局逻辑与视图控制器分开。好的,好的。
据我所知,这翻译成 Swift 是这样的:
// MyView --------------------------------------------------------
class MyView: UIView
let tableView: UITableView!
init(frame: CGRect)
super.init(frame: frame)
tableView = UITableView(frame: frame)
// MyViewController ----------------------------------------------
class MyViewController: UIViewController, UITableViewDataSource
override func loadView()
view = MyView(frame: UIScreen.mainScreen().bounds)
override func viewDidLoad()
super.viewDidLoad()
// this causes the compiler to complain with:
// 'UIView' does not have a member named 'tableView'
self.view.tableView.dataSource = self
问题是我似乎不知道如何告诉视图控制器它的view
是MyView
的一个实例而不是UIView
本身。
尝试失败
这是我迄今为止尝试过的:
我在MyViewController
的顶部试过这个,但出现以下错误:
override var view: MyView!
// error: Cannot override mutable property 'view' of
// type 'UIView' with covariant type 'MyView!'
我在loadView
中尝试过这个,但没有运气:
view = MyView(frame: UIScreen.mainScreen().bounds) as MyView
// this produces the same error as in the original code:
// 'UIView' does not have a member named 'tableView'
那么问题来了
如何告诉 Swift 我正在使用子类 MyView
之一覆盖 MyViewController
的 view
属性?这甚至可能吗?如果没有,为什么不呢?
【问题讨论】:
【参考方案1】:我认为完全相同的实现在 Swift 中可能是不可能的。来自关于覆盖属性的 Swift 书籍部分:
“您必须始终说明您购买的房产的名称和类型 正在覆盖,以使编译器能够检查您的覆盖 匹配具有相同名称和类型的超类属性。”
但是,您可以使用返回视图控制器 view
属性的类型转换版本的计算属性,它几乎一样干净:
class MyViewController: UIViewController, UITableViewDataSource
var myView: MyView! return self.view as MyView
override func loadView()
view = MyView(frame: UIScreen.mainScreen().bounds)
override func viewDidLoad()
super.viewDidLoad()
self.myView.tableView.dataSource = self
【讨论】:
很遗憾没有办法改变view
类。如果我们创建这个控制器的另一个子类怎么办?按照这种模式,我们应该创建类似myMyView
...的唯一解决方案是编写getter func view() -> MyView
,当我们需要再次子类化时,我们可以编写override func view() -> MyAnotherView
。缺点是我们使用self.view()
来查看我们的视图。
这只是给了我一个黑色的视图...似乎不起作用。
Apple 甚至在UITableViewController
中使用了类似的方法。该控制器有一个属性tableView
,它返回与控制器的view
属性完全相同的视图,只是转换为UITableView
。【参考方案2】:
我们可以使用这样的东西吗?
class MyViewController: UIViewController, UIScrollViewDelegate
weak var viewAlias: UIScrollView!
override func loadView()
let scrollView = UIScrollView(frame: UIScreen.mainScreen().bounds)
viewAlias = scrollView
view = scrollView
override func viewDidLoad()
//super.viewDidLoad()
viewAlias.delegate = self
viewAlias.contentSize = view.frame.size
// Do any additional setup after loading the view.
【讨论】:
以上是关于Swift:继承 UIViewController 的根视图的主要内容,如果未能解决你的问题,请参考以下文章
为许多 UIViewController 继承背景颜色和其他属性
带有 Swift 5.0 编译器的 Xcode 10.2 - 协议继承问题
如何在 Swift 5 中创建一个继承自另一个类的 UIImageView 类