我在下面定义的协议存在问题。我有两个要求:
Peer
用作其他类中的类型,同时保持具体类的私有性。 为了满足第二点,我需要使协议符合Equatable
协议。但是当我这样做时,我不能再使用Peer
作为类型,因为它需要被视为通用。这意味着我不能再具有私有的具体实现,并且要求1被打破。
想知道是否有其他人遇到过这个问题并以某种方式解决了这个问题。也许我误解了我在indexOf
...
Group.swift
import Foundation
class Group {
var peers = [Peer]()
init() {
peers.append(PeerFactory.buildPeer("Buddy"))
}
func findPeer(peer: Peer) -> Bool {
if let index = peers.indexOf(peer) {
return true
}
return false
}
}
Peer.swift
import Foundation
protocol Peer {
var name: String { get }
}
class PeerFactory {
static func buildPeer(name: String) -> Peer {
return SimplePeer(name: name)
}
}
private class SimplePeer: Peer {
let name: String
init(name: String) {
self.name = name
}
}
如果indexOf
不 Peer
,则Equatable
出错:
cannot convert value of type 'Peer' to expected argument type '@noescape (Peer) throws -> Bool'
答案 0 :(得分:5)
所以我找到了一个解决方案,通过扩展Equatable
来为CollectionType
类型的元素定义一个新的indexOf
来解决Peer
要求,它利用了其他基于闭包的indexOf
。这本质上是一个便利函数,它使我免于直接使用闭包indexOf
。代码如下:
extension CollectionType where Generator.Element == Peer {
func indexOf(element: Generator.Element) -> Index? {
return indexOf({ $0.name == element.name })
}
}
这当然假设我需要测试相等性的所有内容都可以从Peer
协议获得(对于我的特定用例来说都是如此)。
编辑: Swift 3更新:
extension Collection where Iterator.Element == Peer {
func indexOf(element: Iterator.Element) -> Index? {
return index(where: { $0.name == element.name })
}
}
答案 1 :(得分:1)
我建议您使用公共超类,因此该类可以符合Equatable
class Peer: Equatable {
// Read-only computed property so you can override.
// If no need to override, you can simply declare a stored property
var name: String {
get {
fatalError("Should not call Base")
}
}
// should only be called from subclass
private init() {}
}
private class SimplePeer: Peer {
override var name: String {
get {
return _name
}
}
let _name: String
init(name: String) {
_name = name
super.init()
}
}
func == (lhs: Peer, rhs: Peer) -> Bool {
return lhs.name == rhs.name
}
class PeerFactory {
static func buildPeer(name: String) -> Peer {
return SimplePeer(name: name)
}
}