在Swift中返回instancetype我正在尝试进行此扩展:extension UIViewController{
class func initialize(storyboardName: String, storyboardId: String) -> Self
{
let storyboad = UIStoryboard(name: storyboardName, bundle: nil)
let controller = storyboad.instantiateViewControllerWithIdentifier(storyboardId) as! Self
return controller }}但我得到编译错误:错误:无法将'UIViewController'类型的返回表达式转换为返回类型'Self'可能吗?我也想成为init(storyboardName: String, storyboardId: String)
3 回答
米琪卡哇伊
TA贡献1998条经验 获得超6个赞
类似于在Swift中的类扩展函数中使用'self',您可以定义一个通用的辅助方法,它从调用上下文中推断出self的类型:
extension UIViewController{ class func instantiateFromStoryboard(storyboardName: String, storyboardId: String) -> Self { return instantiateFromStoryboardHelper(storyboardName, storyboardId: storyboardId) } private class func instantiateFromStoryboardHelper<T>(storyboardName: String, storyboardId: String) -> T { let storyboard = UIStoryboard(name: storyboardName, bundle: nil) let controller = storyboard.instantiateViewControllerWithIdentifier(storyboardId) as! T return controller }}
然后
let vc = MyViewController.instantiateFromStoryboard("name", storyboardId: "id")
编译,类型推断为MyViewController
。
Swift 3更新:
extension UIViewController{ class func instantiateFromStoryboard(storyboardName: String, storyboardId: String) -> Self { return instantiateFromStoryboardHelper(storyboardName: storyboardName, storyboardId: storyboardId) } private class func instantiateFromStoryboardHelper<T>(storyboardName: String, storyboardId: String) -> T { let storyboard = UIStoryboard(name: storyboardName, bundle: nil) let controller = storyboard.instantiateViewController(withIdentifier: storyboardId) as! T return controller }}
另一种可能的解决方案,使用unsafeDowncast
:
extension UIViewController{ class func instantiateFromStoryboard(storyboardName: String, storyboardId: String) -> Self { let storyboard = UIStoryboard(name: storyboardName, bundle: nil) let controller = storyboard.instantiateViewController(withIdentifier: storyboardId) return unsafeDowncast(controller, to: self) }}
慕森卡
TA贡献1806条经验 获得超8个赞
Self
是在编译时确定的,而不是运行时。在你的代码中,Self
完全等同于UIViewController
,而不是“恰好调用它的子类”。这将返回UIViewController
,调用者必须将as
它放入正确的子类中。我认为这是你想要避免的(虽然这是“正常的可可”方式,所以只返回UIViewController
可能是最好的解决方案)。
注意:initialize
在任何情况下都不应该命名该函数。这是现有的类函数,NSObject
并且最多会引起混淆,最坏的情况是错误。
但是如果你想避免调用者的话as
,子类化通常不是在Swift中添加功能的工具。相反,您通常需要泛型和协议。在这种情况下,您只需要泛型。
func instantiateViewController<VC: UIViewController>(storyboardName: String, storyboardId: String) -> VC { let storyboad = UIStoryboard(name name: storyboardName, bundle: nil) let controller = storyboad.instantiateViewControllerWithIdentifier(storyboardId) as! VC return controller}
这不是一种类方法。这只是一个功能。这里没有必要上课。
let tvc: UITableViewController = instantiateViewController(name: name, storyboardId: storyboardId)
九州编程
TA贡献1785条经验 获得超4个赞
更清洁的解决方案(至少在视觉上更整洁):
class func initialize(storyboardName: String, storyboardId: String) -> Self { // The absurdity that's Swift's type system. If something is possible to do with two functions, why not let it be just one? func loadFromImpl<T>() -> T { let storyboard = UIStoryboard(name: storyboardName, bundle: nil) return storyboard.instantiateViewController(withIdentifier: storyboardId).view as! T } return loadFromImpl()}
- 3 回答
- 0 关注
- 1477 浏览
添加回答
举报
0/150
提交
取消