【问题标题】:Swift: Subclassing a UIViewController's root viewSwift:继承 UIViewController 的根视图
【发布时间】:2014-06-10 01:47:56
【问题描述】:

tl;dr:我如何告诉 Swift 我正在用 UIView 的子类覆盖 MyViewControllerview 属性?


我想做的事

我非常喜欢为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
    }
}

问题是我似乎不知道如何告诉视图控制器它的viewMyView 的一个实例而不是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 之一覆盖 MyViewControllerview 属性?这甚至可能吗?如果没有,为什么不呢?

【问题讨论】:

    标签: ios uiview uiviewcontroller swift


    【解决方案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() -&gt; MyView,当我们需要再次子类化时,我们可以编写override func view() -&gt; 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.
    
    }
    

    【讨论】:

      猜你喜欢
      • 2019-04-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多