我想创建一个可以存储符合特定协议的对象的类 . 对象应存储在类型化数组中 . 根据Swift文档协议可以用作类型:
因为它是一种类型,所以可以在允许其他类型的许多地方使用协议,包括:作为函数,方法或初始值设定项中的参数类型或返回类型作为常量,变量或属性的类型As数组,字典或其他容器中的项类型
但是,以下生成编译器错误:
协议'SomeProtocol'只能用作通用约束,因为它具有Self或相关类型要求
你怎么解决这个问题:
protocol SomeProtocol: Equatable {
func bla()
}
class SomeClass {
var protocols = [SomeProtocol]()
func addElement(element: SomeProtocol) {
self.protocols.append(element)
}
func removeElement(element: SomeProtocol) {
if let index = find(self.protocols, element) {
self.protocols.removeAtIndex(index)
}
}
}
7 回答
您想要创建一个泛型类,其类型约束要求与其一起使用的类符合
SomeProtocol
,如下所示:你已经遇到了Swift协议问题的一个变种,但尚未找到好的解决方案 .
另请参阅Extending Array to check if it is sorted in Swift?,它包含有关如何解决它的建议,可能适合您的特定问题(您的问题非常通用,也许您可以找到使用这些答案的解决方法) .
在Swift中,有一类特殊的协议,它不提供实现它的类型的多态性 . 此类协议在其定义中使用
Self
或associatedtype
关键字(Equatable
是其中之一) .在某些情况下,可以使用类型擦除的包装器使您的集 Contract 态 . 以下是一个例子 .
我发现有限的解决方案是将协议标记为仅类协议 . 这将允许您使用'==='运算符比较对象 . 我知道这对结构等不起作用,但在我的情况下这已经足够了 .
解决方案非常简单:
我认为你的主要目标是保存符合某些协议的对象集合,添加到此集合并从中删除 . 这是您的客户端“SomeClass”中所述的功能 . Equatable继承需要self,而这个功能不需要 . 我们本可以使用“索引”函数在Obj-C中的数组中完成这项工作,该函数可以使用自定义比较器,但Swift不支持这种功能 . 所以最简单的解决方案是使用字典而不是数组,如下面的代码所示 . 我提供了getElements(),它会返回你想要的协议数组 . 因此,任何使用SomeClass的人都不会知道字典是用于实现的 .
因为在任何情况下,你需要一些区分属性来分隔你的objets,我认为它是“名字” . 创建新的SomeProtocol实例时,请确保执行do element.name =“foo” . 如果未设置名称,您仍然可以创建实例,但不会将其添加到集合中,addElement()将返回“false” .
我在博客文章中找到了一个纯粹的纯粹Swift解决方案:http://blog.inferis.org/blog/2015/05/27/swift-an-array-of-protocols/
诀窍是符合
NSObjectProtocol
,因为它引入了isEqual()
. 因此,您可以编写自己的函数来查找元素并将其删除,而不是使用Equatable
协议及其默认用法==
.以下是
find(array, element) -> Int?
函数的实现:注意:在这种情况下,符合
SomeProtocol
的对象必须从NSObject
继承 .