扩展现有协议以使用默认实现实现另一个协议

Posted

技术标签:

【中文标题】扩展现有协议以使用默认实现实现另一个协议【英文标题】:Extend existing protocols to implement another protocol with default implements 【发布时间】:2016-05-19 14:28:51 【问题描述】:

是否可以通过扩展将协议合规性添加到不同的协议?

例如我们希望 A 遵守 B:

protocol A 
  var a : UIView get


protocol B 
  var b : UIView get

我想为 A 类型的对象提供 B 的默认实现(合规性)

// This isn't possible
extension A : B 
  var b : UIView 
    return self.a
  

动机是在不需要创建我自己的“桥梁”的情况下需要 B 的情况下重用 A 的对象

class MyClass 
  func myFunc(object : A) 
    ...
    ...
    let view = object.a 
    ... do something with view ...

    myFunc(object)      // would like to use an 'A' without creating a 'B'
  

  func myFunc2(object : B) 
    ...
    ...
    let view = object.b
    ... do something with view ...

  

顺便说一句,我们可以扩展一个类来实现协议

class C 
  let C : UIView


// this will work
extension C : B 
  var B : UIView 
    return self.c
  

协议可以提供默认实现

extension A 
  // a default implementation
  var a : UIView 
     return UIView()
  

【问题讨论】:

【参考方案1】:

扩展A时,可以指定类型也符合B

extension A where Self: B 
    var b : UIView 
        return self.a
    

然后让你的类型符合AB,例如

struct MyStruct : A, B 
    var a : UIView 
        return UIView()
    

由于协议扩展,MyStruct 的实例将能够使用ab,即使在MyStruct 中仅实现了a

let obj = MyStruct()
obj.a
obj.b

【讨论】:

我过去使用过“where Self:B...”,但它仍然需要定义您的“MyStruct”。 “MyStruct”是一个“一次性”的桥梁,它需要样板代码。我正在寻找最简洁的方式,这样我就不必创建中间构造来执行映射。理想情况下,我可以像扩展类或结构一样扩展协议。 我有点困惑,在那种情况下你能不能结合使用where Self:B 和协议扩展? @ABakerSmith 你试过编译上面的代码吗?我也尝试过这种方法,但编译器仍然一直告诉 MyStruct 不符合协议 B。我的协议 B 来自第三方并用 Objective C 编写。 @Flow,是的,代码为我编译。确定您在A 的扩展中正确实现了协议B 的要求吗? @ABakerSmith 感谢您的回复。它确实在我的演示项目中使用纯 Swift 编译。但是,我发现,如果在 Objective-C 中声明协议 B,项目将无法编译。 (不幸的是我的情况,协议来自第三方)我在这里创建了一个演示项目github.com/linktoming/Protocol-Demo 协议C是在演示中用Objective-C编写的。【参考方案2】:

你可以让A继承来自B:

protocol A: B  var a: String  get  
protocol B     var b: String  get  

// Default implementation of property b
extension A 
    var b: String  get  return "PropertyB"  



class MyClass: A 
    var a: String  get  return "PropertyA"  

    func printA(obj: A) 
        print(obj.a)
        printB(obj)
    

    func printB(obj: B) 
        print(obj.b)
    


let obj = MyClass()
obj.printA(obj)

由于A 继承自BB 中的每个属性都可以在A 中使用。

【讨论】:

这与 OP 所要求的根本不同。如果他无法控制AB,这将无济于事。 那我想你可以创建一个协议C 实现AB,根据需要使用默认实现? 我不想创建额外的协议。 那你问的是XY question @CodeDifferent 你试过编译上面的代码吗?我正在尝试相同的方法,但编译器一直告诉 A 类不符合 Swift 2 中的协议 B。

以上是关于扩展现有协议以使用默认实现实现另一个协议的主要内容,如果未能解决你的问题,请参考以下文章

扩展 UICollectionViewDataSource 协议以添加默认实现

在 Kotlin Multiplatform 中使用 Swift 协议默认实现

即使在 XCTest 文件中实现类扩展中的方法后,仍会调用协议的默认实现

Swift EXC_BAD_ACCESS,在协议扩展中定义了默认实现

Swift 泛型和协议扩展

Swift 学习笔记(面向协议编程)