目标:创建一个通用的ViewController和TableViewController,它可以从现有的故事板返回自己,并由其他视图控制器进行子类化,并允许它们使用此功能。
class GenericTableViewController: UITableViewController
{
//MARK: Storyboard
class func storyboardName() -> String
{
return ""
}
class func storyboardIdentifier() -> String
{
return ""
}
class func existingStoryboardControllerTemplate() -> Self
{
return UIStoryboard.storyboardWithName(storyboardName()).instantiateViewControllerWithIdentifier(storyboardIdentifier()) as! Self
}
}
问题是..编译器强迫我将Self更改为此“GenericTableViewController”,如果我更改它...它会抱怨我不再返回“Self”。
有什么东西可以解决这个问题吗?
答案 0 :(得分:23)
执行以下操作应该有效:
class func existingStoryboardControllerTemplate() -> Self {
return existingStoryboardControllerTemplate(self)
}
private class func existingStoryboardControllerTemplate<T>(type: T.Type) -> T {
return UIStoryboard(name: storyboardName(), bundle: nil).instantiateViewControllerWithIdentifier(storyboardIdentifier()) as! T
}
基本上,您创建了existingStoryboardControllerTemplate
的通用版本,并添加了一个额外的方法来帮助编译器推断出T
的类型。
答案 1 :(得分:3)
根据Tomas Camin的回答,这里是Swift 3中的UIViewController
扩展名。
extension UIViewController {
class func fromStoryboard(_ name: String, in bundle: Bundle? = nil, withIdentifier id: String? = nil) -> Self? {
return fromStoryboard(UIStoryboard(name: name, bundle: bundle), withIdentifier: id)
}
class func fromStoryboard(_ storyboard: UIStoryboard, withIdentifier id: String? = nil) -> Self? {
return fromStoryboard(storyboard, withIdentifier: id, as: self)
}
private class func fromStoryboard<T>(_ storyboard: UIStoryboard, withIdentifier id: String? = nil, as type: T.Type) -> T? {
return storyboard.instantiateViewController(withIdentifier: id ?? "\(type)") as? T
}
}
如果故事板视图控制器标识符与其类名匹配,则只需使用名称调用类函数from(storyboard:)
。
let viewController = MyCustomViewController.fromStoryboard("Main")
否则,请提供标识符。
let viewController = MyCustomViewController.fromStoryboard("Main", withIdentifier: "ID")
如果您已有故事板的实例,请使用它。
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
let viewController = MyCustomViewController.fromStoryboard(storyboard, withIdentifier: "ID")