簡體   English   中英

創建表示可以打開或關閉的可打包對象的協議

[英]Creating a protocol that represents hashable objects that can be on or off

我正在嘗試創建一個簡單的協議,說明對象是處於“開啟”狀態還是“關閉”狀態。 對此的解釋取決於實施對象。 對於UISwitch ,無論開關是打開還是關閉(duh)。 對於UIButton ,可能是按鈕是否處於selected狀態。 對於Car ,可能是汽車的發動機是否打開,或者即使它是否在移動。 所以我開始創建這個簡單的協議:

protocol OnOffRepresentable {
    func isInOnState() -> Bool
    func isInOffState() -> Bool
}

現在我可以擴展前面提到的UI控件,如下所示:

extension UISwitch: OnOffRepresentable {
    func isInOnState() -> Bool { return on }
    func isInOffState() -> Bool { return !on }
}

extension UIButton: OnOffRepresentable {
    func isInOnState() -> Bool { return selected }
    func isInOffState() -> Bool { return !selected }
}

現在我可以創建這些類型的對象的數組並循環它,檢查它們是打開還是關閉:

let booleanControls: [OnOffRepresentable] = [UISwitch(), UIButton()]
booleanControls.forEach { print($0.isInOnState()) }

大! 現在我想創建一個將這些控件映射到UILabel的字典,以便在控件更改狀態時更改與控件關聯的標簽文本。 所以我去宣布我的字典:

var toggleToLabelMapper: [OnOffRepresentable : UILabel] = [:]
// error: type 'OnOffRepresentable' does not conform to protocol 'Hashable'

哦! 對! 傻我。 好吧,讓我只使用協議組合更新協議(畢竟,我想在這里使用的控件都是Hashable:UISwitch,UIButton等):

protocol OnOffRepresentable: Hashable {
    func isInOnState() -> Bool
    func isInOffState() -> Bool
}

但是現在我得到了一組新的錯誤:

error: protocol 'OnOffRepresentable' can only be used as a generic constraint because it has Self or associated type requirements
error: using 'OnOffRepresentable' as a concrete type conforming to protocol 'Hashable' is not supported

好的...所以我做了一些堆棧溢出挖掘和搜索。 我發現很多文章似乎很有希望,比如Swift中的Set和protocol使用某些協議作為符合其他協議的具體類型是不受支持的 ,我看到有一些關於type erasure好文章似乎正是什么我需要: http://krakendev.io/blog/generic-protocols-and-their-shortcomingshttp://robnapier.net/erasurehttps://realm.io/news/type-erased-wrappers- in-swift /僅舉幾例。

這是我陷入困境的地方。 我已經嘗試閱讀所有這些,並且我已經嘗試創建一個Hashable並且也符合我的OnOffRepresentable協議的類,但我無法弄清楚如何使它全部連接。

我不知道我是否必須使OnOffRepresentable協議繼承自Hashable 它似乎並不喜歡的事,你會希望被作為代表或關也必須是可哈希。 所以在下面的實現中,我只將Hashable一致性添加到類型擦除包裝器中。 這樣,您可以在可能的情況下直接引用OnOffRepresentable項(沒有“只能在通用約束中使用”警告),並且只在需要將它們放入集合中時將它們包裝在HashableOnOffRepresentable類型橡皮擦中或將它們用作字典鍵。

protocol OnOffRepresentable {
    func isInOnState() -> Bool
    func isInOffState() -> Bool
}

extension UISwitch: OnOffRepresentable {
    func isInOnState() -> Bool { return on }
    func isInOffState() -> Bool { return !on }
}

extension UIButton: OnOffRepresentable {
    func isInOnState() -> Bool { return selected }
    func isInOffState() -> Bool { return !selected }
}

struct HashableOnOffRepresentable : OnOffRepresentable, Hashable {

    private let wrapped:OnOffRepresentable
    private let hashClosure:()->Int
    private let equalClosure:Any->Bool

    var hashValue: Int {
        return hashClosure()
    }

    func isInOnState() -> Bool {
        return wrapped.isInOnState()
    }

    func isInOffState() -> Bool {
        return wrapped.isInOffState()
    }

    init<T where T:OnOffRepresentable, T:Hashable>(with:T) {
        wrapped = with
        hashClosure = { return with.hashValue }
        equalClosure = { if let other = $0 as? T { return with == other } else { return false } }
    }
}

func == (left:HashableOnOffRepresentable, right:HashableOnOffRepresentable) -> Bool {
    return left.equalClosure(right.wrapped)
}

func == (left:HashableOnOffRepresentable, right:OnOffRepresentable) -> Bool {
    return left.equalClosure(right)
}

var toggleToLabelMapper: [HashableOnOffRepresentable : UILabel] = [:]

let anySwitch = HashableOnOffRepresentable(with:UISwitch())
let anyButton = HashableOnOffRepresentable(with:UIButton())

var switchLabel:UILabel!
var buttonLabel:UILabel!

toggleToLabelMapper[anySwitch] = switchLabel
toggleToLabelMapper[anyButton] = buttonLabel

使用associatedType創建協議(或使其符合另一個具有像Hashable這樣的associatedType Hashable協議)將使該協議與泛型Hashable

我建議你一個非常簡單的解決方法

OnOffRepresentable

首先,我們不需要2個完全相反的功能? ;)

所以這

protocol OnOffRepresentable {
    func isInOnState() -> Bool
    func isInOffState() -> Bool
}

變成了這個

protocol OnOffRepresentable {
    var on: Bool { get }
}

而且當然

extension UISwitch: OnOffRepresentable { }

extension UIButton: OnOffRepresentable {
    var on: Bool { return selected }
}

將OnOffRepresentable與UILabel配對

現在我們不能使用OnOffRepresentable作為Dictionary Key ,因為我們的協議必須是Hashable 然后讓我們使用另一種數據結構!

let elms: [(OnOffRepresentable, UILabel)] = [
    (UISwitch(), UILabel()),
    (UIButton(), UILabel()),
]

而已。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM