Swift:数组属性,元素同时符合class和多个协议

Swift: Array property with elements conforming to a class and multiple protocols simultaneously

在 Objective-C 中有一种方法可以声明符合 class 和一组协议的变量,如下所示:

BaseClass<Protocol1, Protocol2> *variable = ...

在 Swift 中,我想声明一个数组(实际上是 class 的 属性),其元素类型由此模式定义。

this question 中,有一个解决方案可以通过使 class 通用并相应地限制类型来描述独立 属性 的类型。为了实例化这样的 class ,有必要指定确切的类型。这对于独立 属性 来说不是问题,但在数组中应该可以存储具有不同确切类型的元素。

有没有办法在Swift中表达这个?

在这种情况下,您只想存储符合您的协议的对象,您可以创建另一个继承其他协议的协议,例如

protocol A { }
protocol B { }
protocol C : A, B { }

现在可以创建对应的数组了

var objects : [ C ]

您可以存储任何对象,只要它符合 C-协议,因此也符合 AB

class Foo : X { }
class Bar : X { }

objects.append(Foo()) // [ Foo ]
objects.append(Bar()) // [ Foo, Bar ]

背后的技术是Protocol Inheritance

更新 IMO 这对于 Swift 的 Array 是不可行的。因为,您可以存储从基础 class 或 AnyObject 继承的类型,这不满足您的约束。但是您可以创建一个包装器来检查您尝试附加到数组的对象,如果它不符合约束则拒绝它。

感谢 @SebastianDressler and @Mike-S 我发现在 Swift 中没有直接的表达方式。

不过,您可以像这样限制要添加到数组中的项目的类型:

func addItem<T where T: BaseClass, T: Protocol1, T: Protocol2>(item: T) {
    self.array.append(item)
}

当数组的类型被定义为协议的基 class 之一时,从数组中转换项目是不可能的,因为编译器看不到这些类型之间的任何关系。

为了能够转换为基础 class 或协议之一,有必要将类型声明为 AnyObject

var array: [AnyObject] = []

并且仅当使用 @objc 注释时,转换为协议才有效(参见 )。

我刚遇到这个老问题,因为 Swift 语言在接受部分答案后发生了变化,所以我决定 post 另一个实际上解决了我最初提出的问题的答案。

从版本 4 开始,Swift 支持使用 & 符号组合协议,也可以使用一种 class 类型组合。

class BaseClass {}
protocol Protocol1 {}
protocol Protocol2 {}

class ConformingClass1: BaseClass, Protocol1, Protocol2 {}
class ConformingClass2: BaseClass, Protocol1, Protocol2 {}

// It works for a variable holding a single object.
let object: BaseClass & Protocol1 & Protocol2 = ConformingClass1()

// And it also works for a variable holding an array of objects.
let array: [BaseClass & Protocol1 & Protocol2] = [ConformingClass1(), ConformingClass2()]