所有符合协议的类都继承默认实现

2024-03-23

我已经向所有 UIViewController 子类添加了一个方法,该方法允许我从类及其内部的故事板实例化它。

所有方法都遵循以下格式:

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
}

Instead,我想制定一个协议,Instantiatable,这需要上述方法以及一个变量,storyboardName: String.

那么我想扩展一下这个Instantiatable所以它包含与上面类似的实现。我的目标是我可以声明UIViewController遵守这个协议,我所需要定义的就是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()在非期末班CameraViewController必须返回Self遵守协议Instantiatable

我缺少什么?

Thanks.


Add final


这里的解决方案只是添加final到子类UIViewController(在我的例子中,它是CameraViewController).

这允许您的调用站点正确推断出类型UIViewController无需铸造。在我的示例中,调用站点是:

guard let controller = CameraViewController.instantiate() else {
    return
}

但为什么?


为什么添加最终关键字很重要?

与大家讨论后@阿里软件 https://stackoverflow.com/users/803787/alisoftware,他解释了需要final。 (他还在 Swift mixin 存储库中添加了一个类似的协议,Reusable https://github.com/AliSoftware/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 anyway.

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

所有符合协议的类都继承默认实现 的相关文章

随机推荐

  • 调整 UITextField 的宽度以填充横向工具栏

    In a UIToolbar 我添加了一个UITextField到栏的中间 它被添加为UIBarButtonItem 和另外一个UIBarButtonItem 操作按钮 在它旁边 我在最左边和最右边添加了灵活的空格键按钮项目 它在纵向上看起
  • 页面命令栏与分割视图窗格重叠

    在我的页面中 我有底部命令栏 如果该命令栏打开并且用户单击 SplitView 菜单 则命令栏会覆盖菜单 下面是splitview页面的xaml
  • 如何使用“pdftk”指定附件的描述?

    PDFTK的文档中没有提到如何做到这一点 命令 pdftk file pdf attach files attachDoc pdf to page 2 output 将在原件的第 2 页附加一个文件file pdf并将结果输出到
  • 子查询或 leftjoin 与 group by 哪个更快?

    i have to show running total with the total column in my application so i have used the following queries for finding th
  • ElementNotInteractableException:元素不可交互:自升级到 chromedriver 83 后出现元素大小为零

    我使用以下 docker 映像来运行我的黄瓜测试 https hub docker com r selenium standalone chrome https hub docker com r selenium standalone ch
  • 检测浏览器上的用户不活动 - 纯粹通过 javascript [重复]

    这个问题在这里已经有答案了 在构建监视器时 它将监视用户在浏览器上的任何活动 例如单击按钮或在文本框中键入 而不是鼠标悬停在文档上 因此 如果用户长时间没有活动 会话就会超时 我们需要在没有 jQuery 或类似的东西的情况下做到这一点 我
  • Node Sequelize 查找 $like 通配符

    我正在尝试向 Node Sequelize findAll 添加一个 where like 子句 以类似于 sql 查询select from myData where name like Bob 用下面的代码 let data Array
  • WPF 选项卡控件防止选项卡更改

    我正在尝试为我的应用程序开发一个系统维护屏幕 其中有几个选项卡 每个选项卡代表不同的维护选项 即维护系统用户等 一旦用户单击 编辑 新建 来更改现有记录 我想防止离开当前选项卡 直到用户单击 保存 或 取消 经过一番谷歌搜索后 我找到了一个
  • scrapy-redis程序不会自动关闭

    scrapy redis框架 redis存储的xxx requests已经爬取完毕 但是程序还在运行 如何自动停止程序 而不是一直在运行 运行代码 2017 08 07 09 17 06 scrapy extensions logstats
  • 扑。文件 containsSync() 始终返回 false

    这就是我现在面临的问题 我有一个名为 assets 的文件夹 在该文件夹内有一个名为 no icon png 的图像 我已将其添加到 pubspec yaml 中 如下所示 flutter assets assets teamShields
  • R:dplyr 按日期范围分组

    我正在尝试根据 2016 04 10 和 2016 04 24 按 3 个日期范围对数据框进行分组 df lt structure list date structure c 16803 16810 16817 16824 16831 16
  • 如何设置pagingtoolbar输入项值

    我这里有问题 我在分页工具栏上绑定了一个商店 该商店有多个页面 例如我将当前页面更改为第2页 然后通过搜索表单更改只有一页的商店内容 网格加载收集数据 但输入项仍然显示它位于第 2 页 我希望它在调用搜索事件后显示 1 我不想使用 stor
  • protobuf-net 中 List 的 .proto 等价物是什么?

    为了保持一定的一致性 我们对许多对象模型使用代码生成 其分支之一是通过单独的生成模块为 ProtocolBuffers 生成 proto 文件 但在这一点上 我很难理解当它发生时如何实现生成List
  • 如何在改变字体大小的块元素中垂直居中文本?

    我对垂直居中文本的常用方法是使用等于容器高度的行高 因此 容器具有 height 60px line height 60px 并且子元素有 line height 60px 这样可行 但如果你增加font size高于 1em 那就搞砸了
  • -> <- 运算符的作用是什么?

    我最近发现了以下代码 IntPredicate neg x gt x lt x 这是什么 某种反向双 lambda 没有 gt lt 操作员 那第一 gt 只是 Java 8 中引入的 lambda 语法 而第二个 lt 是 小于 的误导性
  • 如何写入LLDB中的XMM寄存器

    我正在尝试使用 LLDB API 从 python 中的寄存器读取和写入值 对于通用寄存器 我一直在使用frame register register name value读取和写入寄存器值 这对我来说很成功 然而 当我接近浮点寄存器时 我
  • 向 csv 文件中的每个元素添加引号和制表符

    如何使用 python 将引号和制表符添加到 csv 文件中的每个元素 例如 我想制作这个 csv 样本 TitleA TitleB TitleC TitleD TitleE Data1 Data2
  • Postgresql - 将 varchar 列的大小更改为更短的长度

    我有一个关于ALTER TABLE在一个非常大的表 几乎 3000 万行 上执行命令 它的其中一列是varchar 255 我想将其调整为varchar 40 基本上 我想通过运行以下命令来更改我的专栏 ALTER TABLE mytabl
  • 在 WebMatrix 中由 C# 生成选择查询后,在带有空格的列上使用 row.ColumnName

    我编译了一个查询数据库的字符串 如下所示 stringCompiler SELECT FROM SomeTable 问题是某些列的名称中包含空格 即 城市标签号 使用 db Query 语句后如何调用它 例子 foreach var row
  • 所有符合协议的类都继承默认实现

    我已经向所有 UIViewController 子类添加了一个方法 该方法允许我从类及其内部的故事板实例化它 所有方法都遵循以下格式 class func instantiateFromStoryboard gt CameraViewCon