2015-10-23 84 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