我已经向所有 UIViewController 子类添加了一个方法,该方法允许我从类及其内部的 Storyboard实例化它。
所有方法都遵循以下格式:
class func instantiateFromStoryboard() -> CameraViewController? {
let storyboard = UIStoryboard(name: "Camera", bundle: nil)
let initial = storyboard.instantiateInitialViewController()
guard let controller = initial as? CameraViewController else {
return nil
}
return controller
}
相反,我想创建一个可实例化
协议(protocol),它需要上述方法以及一个变量storyboardName: String
。
然后,我想扩展这个Instantiatable
,使其包含与上面类似的实现。我的目标是我可以声明 UIViewController
遵守此协议(protocol),而我必须定义的只是 storyboardName
。
我觉得我已经接近这个实现了:
protocol Instantiatable {
var storyboardName: String { get }
func instantiateFromStoryboard() -> Self?
}
extension Instantiatable where Self: UIViewController {
func instantiateFromStoryboard() -> Self? {
let storyboard = UIStoryboard(name: storyboardName, bundle: nil)
let initial = storyboard.instantiateInitialViewController()
guard let controller = initial as? Self else {
return nil
}
return controller
}
}
但是,当我尝试向 CameraViewController
添加一致性时,出现错误:
Method
instantiateFromStoryboard()
in non-final classCameraViewController
must returnSelf
to conform to protocolInstantiatable
我错过了什么?
谢谢。
最佳答案
添加final
这里的解决方案只是添加 final
到子类UIViewController
(在我的示例中,它是 CameraViewController
)。
这允许您的调用站点正确推断 UIViewController
的类型无需类型转换。在我的示例中,调用站点是:
guard let controller = CameraViewController.instantiate() else {
return
}
但是,为什么?
为什么添加最终关键字很重要?
与@AliSoftware讨论后,他解释了 final
的必要性。 (他还在 Swift mixin 存储库中添加了类似的协议(protocol) Reusable 。)
编译器关心您的自定义 VC 是否为 final
确保Self
要求Instantiatable
提及项可以静态推断,也可以不静态推断。
在一个例子中:
class ParentVC: UIViewController, Instantiatable {
// Because of Instantiatable, this class automatically has a method
// with this signature:
func instantiate() -> ParentVC // here, the "Self" coming from the Protocol, meaning "the conforming class", which is solved as "ParentVC"
}
class ChildVC: ParentVC {
// Error: It inherits from ParentVC, and has to conform
// to Instantiatable as a Parent
func instantiate() -> ParentVC
// but, it also has this from being a Instantiatable object itself
func instantiate() -> ChildVC
// thus, the compiler cannot solve what "Self" should resolve to here,
// either ParentVC or ChildVC.
//
// Also, it can generate problems in various contexts being "of
// both types" here, which is why it's not permitted
}
为什么添加final就可以了
您的自定义 VC 直接继承自
UIViewController
,但不需要进一步子类化,因此您应该将其标记为final
无论如何。或者,您正在创建父摘要
CommonVC
。您打算让多个子项(class CustomVC1: CommonVC
、class CustomVC2: CommonVC
)继承它,但在这种情况下CommonVC
是抽象的,可能不会直接实例化。因此,它不是被标记为Instantiatable
的那个。 ,并且您应该标记CustomVC1
等等,您打算实例化为final
+Instantiatable
相反。
关于ios - 所有符合协议(protocol)的类都继承默认实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38287283/