ios – 如何在Swift中子类化UITableViewController

我想要子类化UITableViewController,并能够通过调用没有参数的默认初始化程序来实例化它。

class TestViewController: UITableViewController {
    convenience init() {
        self.init(style: UITableViewStyle.Plain)
    }
}

从Xcode 6 Beta 5,上面的例子不再工作。

Overriding declaration requires an 'override' keyword
Invalid redeclaration of 'init()'
注意这个bug在iOS 9中是固定的,所以整个事情在这一点上将是无效的。下面的讨论仅适用于特定的系统和版本的Swift,它被明确地调整。

这显然是一个错误,但也有一个非常容易的解决方案。我将解释问题,然后给出解决方案。请注意,我写这个Xcode 6.3.2和Swift 1.2;从Swift第一次出来的那一天起,苹果已经在地图上,所以其他版本的行为会有所不同。

存在的理由

你将手动实例化UITableViewController(也就是说,通过在代码中调用它的初始化器)。你想要子类化UITableViewController,因为你有你想要的实例属性。

问题

所以,你从一个实例属性开始:

class MyTableViewController: UITableViewController {
    let greeting : String
}

这没有默认值,所以你必须写一个初始值设定器:

class MyTableViewController: UITableViewController {
    let greeting : String
    init(greeting:String) {
        self.greeting = greeting
    }
}

但这不是一个合法的初始化 – 你必须调用super。让我们说你调用super是调用init(style :)。

class MyTableViewController: UITableViewController {
    let greeting : String
    init(greeting:String) {
        self.greeting = greeting
        super.init(style: .Plain)
    }
}

但是你仍然无法编译,因为你有一个需求来实现init(coder :)。所以你做:

class MyTableViewController: UITableViewController {
    let greeting : String
    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    init(greeting:String) {
        self.greeting = greeting
        super.init(style: .Plain)
    }
}

您的代码现在编译!你现在很高兴(你认为)通过调用你写的初始化器实例化这个表视图控制器子类:

let tvc = MyTableViewController(greeting:"Hello there")

一切看起来都很快乐,直到你运行应用程序,在这一点你崩溃与这个消息:

fatal error: use of unimplemented initializer init(nibName:bundle:)

什么导致崩溃,为什么你不能解决它

崩溃是由Cocoa中的错误引起的。你不知道,init(style :)本身调用init(nibName:bundle :)。它称之为自我。这是你 – MyTableViewController。但是MyTableViewController没有init(nibName:bundle :)的实现。并且不继承init(nibName:bundle :),因为您已经提供了一个指定的初始化程序,从而切断继承。

你唯一的解决方案是实现init(nibName:bundle :)。但是你不能,因为该实现将需要你设置实例属性问候 – 你不知道什么设置它。

简单的解决方案

简单的解决方案 – 几乎太简单,这就是为什么它是如此难以想到 – 是:不要子类UITableViewController。为什么这是一个合理的解决方案?因为你从来没有真正需要在第一个子类。 UITableViewController是一个很大程度上无意义的类;它不会为你做任何你不能为自己做的事情。

所以,现在我们将重写我们的类作为一个UIViewController子类。我们仍然需要一个表视图作为我们的视图,所以我们将在loadView中创建它,我们也将它挂接在那里。更改标记为已加星标的评论:

class MyViewController: UIViewController, UITableViewDelegate, UITableViewDataSource { // *
    let greeting : String
    weak var tableView : UITableView! // *
    init(greeting:String) {
        self.greeting = greeting
        super.init(nibName:nil, bundle:nil) // *
    }
    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    override func loadView() { // *
        self.view = UITableView(frame: CGRectZero, style: .Plain)
        self.tableView = self.view as! UITableView
        self.tableView.delegate = self
        self.tableView.dataSource = self
    }
}

当然,你还需要添加最少的数据源方法。我们现在像这样实例化我们的类:

let tvc = MyViewController(greeting:"Hello there")

我们的项目编译和运行没有障碍。问题解决了!

反对 – 不

你可能反对,通过不使用UITableViewController,我们失去了从故事板获得原型单元格的能力。但这是没有异议,因为我们从来没有这种能力。记住,我们的假设是,我们是子类化并调用我们自己的子类的初始化器。如果我们从故事板中获得原型单元,故事板将通过调用init(coder :)来实例化我们,这个问题从来不会出现。

http://stackoverflow.com/questions/25139494/how-to-subclass-uitableviewcontroller-in-swift

本站文章除注明转载外,均为本站原创或编译
转载请明显位置注明出处:ios – 如何在Swift中子类化UITableViewController