sno*_*nod 130 generics ios swift swift-protocols
我想创建一个可以存储符合特定协议的对象的类.对象应存储在类型化数组中.根据Swift文档协议可以用作类型:
因为它是一种类型,所以您可以在允许其他类型的许多地方使用协议,包括:
- 作为函数,方法或初始值设定项中的参数类型或返回类型
- 作为常量,变量或属性的类型
- 作为数组,字典或其他容器中的项类型
但是,以下生成编译器错误:
协议'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)
}
}
}
Run Code Online (Sandbox Code Playgroud)
Dar*_*ust 46
你已经遇到了Swift协议问题的一个变种,但尚未找到好的解决方案.
另请参阅扩展数组以检查它是否在Swift中排序?,它包含有关如何解决它的建议,可能适合您的特定问题(您的问题非常通用,也许您可以找到使用这些答案的解决方法).
Nat*_*ook 32
您想要创建一个泛型类,其类型约束要求与其一起使用的类符合SomeProtocol,如下所示:
class SomeClass<T: SomeProtocol> {
typealias ElementType = T
var protocols = [ElementType]()
func addElement(element: ElementType) {
self.protocols.append(element)
}
func removeElement(element: ElementType) {
if let index = find(self.protocols, element) {
self.protocols.removeAtIndex(index)
}
}
}
Run Code Online (Sandbox Code Playgroud)
wer*_*ver 13
在Swift中有一类特殊的协议,它不提供实现它的类型的多态性.这些协议在其定义中使用Self或使用associatedtype关键字(并且Equatable是其中之一).
在某些情况下,可以使用类型擦除的包装器使您的集合同态.以下是一个例子.
// This protocol doesn't provide polymorphism over the types which implement it.
protocol X: Equatable {
var x: Int { get }
}
// We can't use such protocols as types, only as generic-constraints.
func ==<T: X>(a: T, b: T) -> Bool {
return a.x == b.x
}
// A type-erased wrapper can help overcome this limitation in some cases.
struct AnyX {
private let _x: () -> Int
var x: Int { return _x() }
init<T: X>(_ some: T) {
_x = { some.x }
}
}
// Usage Example
struct XY: X {
var x: Int
var y: Int
}
struct XZ: X {
var x: Int
var z: Int
}
let xy = XY(x: 1, y: 2)
let xz = XZ(x: 3, z: 4)
//let xs = [xy, xz] // error
let xs = [AnyX(xy), AnyX(xz)]
xs.forEach { print($0.x) } // 1 3
Run Code Online (Sandbox Code Playgroud)
alm*_*mas 12
我找到的有限解决方案是将协议标记为仅类协议.这将允许您使用'==='运算符比较对象.我知道这对结构等不起作用,但在我的情况下这已经足够了.
protocol SomeProtocol: class {
func bla()
}
class SomeClass {
var protocols = [SomeProtocol]()
func addElement(element: SomeProtocol) {
self.protocols.append(element)
}
func removeElement(element: SomeProtocol) {
for i in 0...protocols.count {
if protocols[i] === element {
protocols.removeAtIndex(i)
return
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
解决方案非常简单:
protocol SomeProtocol {
func bla()
}
class SomeClass {
init() {}
var protocols = [SomeProtocol]()
func addElement<T: SomeProtocol where T: Equatable>(element: T) {
protocols.append(element)
}
func removeElement<T: SomeProtocol where T: Equatable>(element: T) {
protocols = protocols.filter {
if let e = $0 as? T where e == element {
return false
}
return true
}
}
}
Run Code Online (Sandbox Code Playgroud)
从Swift 5.7 / Xcode 14开始,现在可以使用any.
protocol SomeProtocol: Equatable {
func bla()
}
class SomeClass {
var protocols = [any SomeProtocol]()
func addElement(element: any SomeProtocol) {
protocols.append(element)
}
func removeElement(element: any SomeProtocol) {
if let index = find(protocols, element) {
protocols.remove(at: index)
}
}
}
Run Code Online (Sandbox Code Playgroud)