【问题标题】:How to require that a protocol can only be adopted by a specific class如何要求协议只能被特定类采用
【发布时间】:2016-02-01 15:09:51
【问题描述】:

我想要这个协议:

protocol AddsMoreCommands {
     /* ... */
}

仅由继承自类UIViewController 的类采用。 This page 告诉我,我可以指定它只被一个类(而不是一个结构体)采用,方法是写

protocol AddsMoreCommands: class {
}

但我看不出如何要求它只被特定类采用。 That page later 谈到在协议扩展中添加 where 子句以检查一致性,但我也看不出如何调整它。

extension AddsMoreCommands where /* what */ {
}

有没有办法做到这一点? 谢谢!

【问题讨论】:

    标签: swift generics protocols


    【解决方案1】:
    protocol AddsMoreCommands: class {
        // Code
    }
    
    extension AddsMoreCommands where Self: UIViewController {
        // Code
    }
    

    【讨论】:

    • 我差点搞定了...我写了self 而不是Self :-( 非常感谢,效果很好!
    • 对我来说,当我将它与强制转换结合使用时,这会导致一些语法上的奇怪。
    • 如果您需要在协议中包含属性,这将不起作用,因为扩展不能包含存储的属性。
    • 它可以存储属性你只需要使用这个:objc_getAssociatedObject(self, &KeyName) as?属性类型
    • 文档改为使用AnyObject 而不是class -> docs.swift.org/swift-book/LanguageGuide/Protocols.html#ID281。但目前这两个版本的行为相同,没有弃用警告。
    【解决方案2】:

    这也可以在没有扩展的情况下实现:

    protocol AddsMoreCommands: UIViewController {
        // code
    }
    

    与以下内容完全相同:

    protocol AddsMoreCommands where Self: UIViewController {
       // code
    }
    

    我通常使用第一个选项,IIRC 我不久前在 Swift 文档上读到,当约束为 Self 时,这是推荐的方式,如果是其他约束,例如 associate types,则当 where 可以是用过。

    请注意,由于UIViewController 也是class,因此可以为委托等弱属性实现此协议。

    EDITED 2021/01/05:以前发布的解决方案有一个警告,我已将其删除并使用这个不会产生任何警告的解决方案。

    【讨论】:

    • 我点击了一个两年前的问题并找到了一个小时前发布的完美解决方案,这是多么巧合?
    • Xcode 9.1 现在就这句话给我一个警告:冗余布局约束 'Self' : 'AnyObject'。布局约束约束“Self”:此处隐含“AnyObject”。将我的代码更改为接受答案的格式似乎更好。
    • 从 Xcode 9.1 开始,仅类协议现在使用 AnyObject 而不是 classprotocol AddsMoreCommands: AnyObject where Self: UIViewController { // code }
    • @dodgio 仍然使用AnyObject得到同样的警告
    • @DávidPásztor 你是对的,但是如果你想在诸如委托之类的结构模式上使用它,为了能够使属性变弱,有必要明确添加“类”:)跨度>
    【解决方案3】:

    由于上一个答案中的一个问题,我最终得到了这个声明:

    protocol AddsMoreCommands where Self : UIViewController { 
        // protocol stuff here  
    }
    

    Xcode 9.1 中没有警告

    【讨论】:

    • 如果我错了,请纠正我,但是与上述解决方案(在 Xcode 9.1 及更高版本中生成警告)相比的问题是您不能将委托声明为弱吗?
    • 另外,当我将此解决方案与 Swift 4.1 一起使用时,我需要将 AddsMoreCommands 的属性转换为我想避免的 UIViewController...
    • 为了避免类型转换,你可以这样做:typealias AddsMoreCommandsViewController = UIViewController & AddsMoreCommands
    【解决方案4】:

    现在在 Swift 5 中,您可以通过以下方式实现:

    protocol AddsMoreCommands: UIViewController {
         /* ... */
    }
    

    非常方便。

    【讨论】:

    • 这两者有什么区别?扩展 AddsMoreCommands where Self: UIViewController { // Code } AND protocol AddsMoreCommands: UIViewController { /* ... */ } 谢谢你。
    • 我想你的意思是protocol而不是extension,如果是这样的话,有人已经answered it
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-05
    • 2018-05-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多