2015-10-23 85 views
3

我在下面定义的协议中遇到问题。我有两个要求:Swift 2 - 符合Equatable问题的协议

  1. 我希望能够使用的协议Peer为其他类类型,同时保持具体类私有。
  2. 我想将协议存储在一个数组中,并能够确定实例的索引。

为了满足第二点,我需要使协议符合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如果PeerEquatable

cannot convert value of type 'Peer' to expected argument type '@noescape (Peer) throws -> Bool' 
+0

阵列-的协议可能会出现问题。您是否观看基于协议的Swift编程的WWDC 2015视频? – matt

+0

几个月前我看过它。我会复赛,看看它是否给我任何线索。 – Mark

+0

视频的核心部分就是一系列协议采用者可以平等化的问题。但要注意的是:协议阵列是有问题的。 :) – matt

回答

5

所以我通过扩展CollectionType定义一个新的indexOf的元素Peer类型,它利用了其他基于封闭indexOf的找到了一个解决方案,使周围的Equatable要求。这本质上是一种便利功能,它使我无法直接使用关闭indexOf。下面的代码:

extension CollectionType where Generator.Element == Peer { 
    func indexOf(element: Generator.Element) -> Index? { 
     return indexOf({ $0.name == element.name }) 
    } 
} 

当然,这是假设一切,我需要测试平等可以从Peer协议(这是真的为我的具体使用情况)来获得。

编辑:更新斯威夫特3:

extension Collection where Iterator.Element == Peer { 
    func indexOf(element: Iterator.Element) -> Index? { 
     return index(where: { $0.name == element.name }) 
    } 
} 
+0

在一般情况下,你需要编写自己的扩展来处理你的协议,用于任何需要类型实现Equatable的任何操作,然后手动执行相等性检查。 – Mark

+0

这个答案基本上是我建议你观看的WWDC 2015视频中给出的解决方案,不是吗? – matt

+0

没有不完全。他们通过在协议中定义一个isEqual方法来解决'Equatable Drawable'问题,然后他们为'Drawable'和'Equatable'都编写了一个协议扩展来处理比较。我在这里做的是完全避免使用'equatable'来满足'indexOf'方法的特定需求。这是我参考的视频,解决方案从38:30开始:https://developer.apple.com/videos/play/wwdc2015-408/ – Mark

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) 
    } 
} 
+0

虽然必要的fatalError是一种设计气味,但它也能起作用。如果我发现有很多具有Equatable需求的函数,我需要为我的协议重写,这可能是一个更可行的选项。 – Mark