ios - 所有符合协议(protocol)的类都继承默认实现

标签 ios swift protocols swift-protocols

我已经向所有 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 class CameraViewController must return Self to conform to protocol Instantiatable

我错过了什么?

谢谢。

最佳答案

添加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就可以了


  1. 您的自定义 VC 直接继承自 UIViewController ,但不需要进一步子类化,因此您应该将其标记为 final无论如何。

  2. 或者,您正在创建父摘要 CommonVC 。您打算让多个子项( class CustomVC1: CommonVCclass CustomVC2: CommonVC )继承它,但在这种情况下 CommonVC是抽象的,可能不会直接实例化。因此,它不是被标记为 Instantiatable 的那个。 ,并且您应该标记 CustomVC1等等,您打算实例化为 final + Instantiatable相反。

关于ios - 所有符合协议(protocol)的类都继承默认实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38287283/

相关文章:

ios - Swift 协议(protocol)中 IBAction 的更好策略是什么?

ios - 非常坚持 ADT 打包和 iOS 上的 AIR native 扩展

Ios将标签(歌曲标题)从右侧移动到左侧?

ios - 如何保护我的 iOS 应用程序中的数字内容 (PDF)?

ios - 后台运行的应用程序和用户通知。

xml - 无法在 Swift 中使用 SWXMLHash 返回解析 XML 的值

ios - 应用程序卡在带有 Xcode 11 beta 的 iOS 13 beta 模拟器上,但在带有 Xcode 10 的 iOS 13 beta 模拟器上运行良好

ios - TTAtributedLabel 设置多色使用 UIColor,它在 header 中用 MACRO 定义?

HTTPbis - bis 是什么意思?

swift - 为任意基于 Int 的枚举定义 Swift 协议(protocol)