12

オブジェクトが「オン」状態か「オフ」状態かを示す簡単なプロトコルを作成しようとしています。それが何であるかの解釈は、実装するオブジェクトによって異なります。の場合UISwitch、それはスイッチがオンかオフかです (当然)。の場合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

わかりました...スタックオーバーフローの掘り出しと検索を行います。Set and protocols in SwiftUsing some protocol as a specific type conforming to another protocol is not supportedなど、有望と思われる多くの記事を見つけtype erasureました。 : http://krakendev.io/blog/generic-protocols-and-their-shortcomingshttp://robnapier.net/erasure、およびhttps://realm.io/news/type-erased-wrappers-in-迅速/ほんの数例を挙げると。

これは私が立ち往生するところです。私はこれらすべてを読んでみました。Hashableまた、プロトコルに準拠するクラスを作成しようとしましたOnOffRepresentableが、すべてを接続する方法がわかりません。

4

2 に答える 2

3

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
于 2016-08-20T00:11:12.360 に答える
0

を使用してプロトコルを作成すると(またはlikeassociatedTypeを持つ別のプロトコルに適合させると)、そのプロトコルはジェネリックと非常に相性が悪くなります。associatedTypeHashable

非常に簡単な回避策を提案します

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 にペアリングする

プロトコルは でなければならないため、現在はOnOffRepresentableasKeyを使用できません。それでは、別のデータ構造を使用しましょう!DictionaryHashable

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

それでおしまい。

于 2016-08-20T00:35:42.617 に答える