如何在 Swift 中使用具有相同协议变量的多个协议?
How to use multiple protocols in Swift with same protocol variables?
在 swift 中,我正在实施两个协议,GADCustomEventInterstitial
和 GADCustomEventBanner
。
这两个协议都需要一个名为 delegate
的 属性。 delegate
在每个协议中都是不同的类型,因此会产生冲突。
class ChartBoostAdapter : NSObject, GADCustomEventInterstitial, GADCustomEventBanner, ChartboostDelegate{
var delegate:GADCustomEventInterstitialDelegate?; // Name conflict
var delegate:GADCustomEventBannerDelegate?; // Name conflict
override init(){
}
...
}
简单的回答是你不能。
也许一个协议依赖于另一个协议,在这种情况下,您将使用依赖协议作为您的委托类型。
They are libraries/frameworks it's not my definition
那么显然你不能让同一个class同时采用两种协议。但你真的不需要。只需将此功能分成两个不同的 classes,这显然是这些协议的设计者的意图。您应该有一个 class 采用 GADCustomEventInterstitial 并具有 its delegate
和 另一个 class采用 GADCustomEventBanner
并具有 其 delegate
。你有什么理由试图强迫它们成为同一个 class?与使用框架的所有事情一样,不要对抗框架,服从它。
其实是可以的,我刚遇到同样的情况。我有两个不同但有点相关的协议。在某些情况下,我需要两者都由委托实现,而在其他情况下,我只需要一个,我不想拥有两个属性,例如... delegate1, delegate2.
您需要做的是创建另一个继承自这两个协议的组合协议:
protocol ChartBoostAdapterDelegate: GADCustomEventInterstitialDelegate, GADCustomEventBannerDelegate { }
class ChartBoostAdapter : NSObject, GADCustomEventInterstitial, GADCustomEventBanner, ChartboostDelegate {
weak var delegate: ChartBoostAdapterDelegate?
override init(){
}
...
}
请注意,如果您处于 Swift-only 环境中,这可以使用 Mixins 解决(自 Swift 2.0 起可能)。只要你需要将代码桥接到 Obj-C 就无法解决,因为此问题在 Obj-C 中无法解决。然而,这通常可以通过包装器 class 来解决,稍后我将展示它。
让我们将其分解为一个最简单的例子:
import Foundation
@objc
protocol ProtoA {
var identifier: String { get }
}
@objc
protocol ProtoB {
var identifier: UUID { get }
}
@objc
class ClassA: NSObject, ProtoA, ProtoB {
let identifier = "ID1"
let identifier = UUID()
}
上面的代码将失败,因为没有两个属性可以具有相同的名称。如果我只声明 identifier
一次并使它成为 String
,编译器会抱怨 ClassA
不符合 ProtoB
,反之亦然。
但这里是 Swift-only 实际有效的代码:
import Foundation
protocol ProtoA {
var identifier: String { get }
}
protocol ProtoB {
var identifier: UUID { get }
}
class ClassA {
let stringIdentifier = "ID1"
let uuidIdentifier = UUID()
}
extension ProtoA where Self: ClassA {
var identifier: String {
return self.stringIdentifier
}
}
extension ProtoB where Self: ClassA {
var identifier: UUID {
return self.uuidIdentifier
}
}
extension ClassA: ProtoA, ProtoB { }
当然,你不能那样做:
let test = ClassA()
print(test.identifier)
编译器会说 ambigous use of 'identifier'
,因为它不知道您要访问哪个标识符,但您可以这样做:
let test = ClassA()
print((test as ProtoA).identifier)
print((test as ProtoB).identifier)
输出将是
ID1
C3F7A09B-15C2-4FEE-9AFF-0425DF66B12A
符合预期。
现在要将 ClassA
实例公开给 Obj-C,您需要包装它:
class ClassB: NSObject {
var stringIdentifier: String { return self.wrapped.stringIdentifier }
var uuidIdentifier: UUID { return self.wrapped.uuidIdentifier }
private let wrapped: ClassA
init ( _ wrapped: ClassA )
{
self.wrapped = wrapped
}
}
extension ClassA {
var asObjCObject: ClassB { return ClassB(self) }
}
如果您将它直接放入 ClassA
的 class 声明中,您甚至可以将其存储为 属性,这样您就不必再次重新创建它但这会使一切变得复杂,因为 ClassB
可能只持有对包装对象的弱引用,否则你会创建一个保留循环,并且两个对象都不会被释放。最好将其缓存在 Obj-C 代码中的某处。
为了解决您的问题,可以使用类似的包装器方法构建一个大师 class 并且这位大师 class 分发了两个包装器 class,一个符合 GADCustomEventInterstitial
和一个符合 GADCustomEventBanner
但它们没有任何内部状态或逻辑,它们都使用主 class 作为存储后端并将所有请求传递给实现的 class所有必需的逻辑。
在 swift 中,我正在实施两个协议,GADCustomEventInterstitial
和 GADCustomEventBanner
。
这两个协议都需要一个名为 delegate
的 属性。 delegate
在每个协议中都是不同的类型,因此会产生冲突。
class ChartBoostAdapter : NSObject, GADCustomEventInterstitial, GADCustomEventBanner, ChartboostDelegate{
var delegate:GADCustomEventInterstitialDelegate?; // Name conflict
var delegate:GADCustomEventBannerDelegate?; // Name conflict
override init(){
}
...
}
简单的回答是你不能。
也许一个协议依赖于另一个协议,在这种情况下,您将使用依赖协议作为您的委托类型。
They are libraries/frameworks it's not my definition
那么显然你不能让同一个class同时采用两种协议。但你真的不需要。只需将此功能分成两个不同的 classes,这显然是这些协议的设计者的意图。您应该有一个 class 采用 GADCustomEventInterstitial 并具有 its delegate
和 另一个 class采用 GADCustomEventBanner
并具有 其 delegate
。你有什么理由试图强迫它们成为同一个 class?与使用框架的所有事情一样,不要对抗框架,服从它。
其实是可以的,我刚遇到同样的情况。我有两个不同但有点相关的协议。在某些情况下,我需要两者都由委托实现,而在其他情况下,我只需要一个,我不想拥有两个属性,例如... delegate1, delegate2.
您需要做的是创建另一个继承自这两个协议的组合协议:
protocol ChartBoostAdapterDelegate: GADCustomEventInterstitialDelegate, GADCustomEventBannerDelegate { }
class ChartBoostAdapter : NSObject, GADCustomEventInterstitial, GADCustomEventBanner, ChartboostDelegate {
weak var delegate: ChartBoostAdapterDelegate?
override init(){
}
...
}
请注意,如果您处于 Swift-only 环境中,这可以使用 Mixins 解决(自 Swift 2.0 起可能)。只要你需要将代码桥接到 Obj-C 就无法解决,因为此问题在 Obj-C 中无法解决。然而,这通常可以通过包装器 class 来解决,稍后我将展示它。
让我们将其分解为一个最简单的例子:
import Foundation
@objc
protocol ProtoA {
var identifier: String { get }
}
@objc
protocol ProtoB {
var identifier: UUID { get }
}
@objc
class ClassA: NSObject, ProtoA, ProtoB {
let identifier = "ID1"
let identifier = UUID()
}
上面的代码将失败,因为没有两个属性可以具有相同的名称。如果我只声明 identifier
一次并使它成为 String
,编译器会抱怨 ClassA
不符合 ProtoB
,反之亦然。
但这里是 Swift-only 实际有效的代码:
import Foundation
protocol ProtoA {
var identifier: String { get }
}
protocol ProtoB {
var identifier: UUID { get }
}
class ClassA {
let stringIdentifier = "ID1"
let uuidIdentifier = UUID()
}
extension ProtoA where Self: ClassA {
var identifier: String {
return self.stringIdentifier
}
}
extension ProtoB where Self: ClassA {
var identifier: UUID {
return self.uuidIdentifier
}
}
extension ClassA: ProtoA, ProtoB { }
当然,你不能那样做:
let test = ClassA()
print(test.identifier)
编译器会说 ambigous use of 'identifier'
,因为它不知道您要访问哪个标识符,但您可以这样做:
let test = ClassA()
print((test as ProtoA).identifier)
print((test as ProtoB).identifier)
输出将是
ID1
C3F7A09B-15C2-4FEE-9AFF-0425DF66B12A
符合预期。
现在要将 ClassA
实例公开给 Obj-C,您需要包装它:
class ClassB: NSObject {
var stringIdentifier: String { return self.wrapped.stringIdentifier }
var uuidIdentifier: UUID { return self.wrapped.uuidIdentifier }
private let wrapped: ClassA
init ( _ wrapped: ClassA )
{
self.wrapped = wrapped
}
}
extension ClassA {
var asObjCObject: ClassB { return ClassB(self) }
}
如果您将它直接放入 ClassA
的 class 声明中,您甚至可以将其存储为 属性,这样您就不必再次重新创建它但这会使一切变得复杂,因为 ClassB
可能只持有对包装对象的弱引用,否则你会创建一个保留循环,并且两个对象都不会被释放。最好将其缓存在 Obj-C 代码中的某处。
为了解决您的问题,可以使用类似的包装器方法构建一个大师 class 并且这位大师 class 分发了两个包装器 class,一个符合 GADCustomEventInterstitial
和一个符合 GADCustomEventBanner
但它们没有任何内部状态或逻辑,它们都使用主 class 作为存储后端并将所有请求传递给实现的 class所有必需的逻辑。