web-dev-qa-db-ja.com

Xcode 6.3 Beta2でSwiftのスーパークラスからセッターをオーバーライドするにはどうすればよいですか?

私のSuerClassはUICollectionViewCellで、次のプロパティがあります。

var selected: Bool

私のクラスは

MyClass : UICollectionViewCell {

  func setSelected(selected: Bool) { 
    super.selected = selected
    // do something
 }

}

前者はXcode6.2でうまく機能しましたが、Xcode6.3Beta2ではエラーが発生します。

Method 'setSelected' with Objective-C selector 'setSelected:' conflicts with setter for 'selected' from superclass 'UICollectionViewCell' with the same Objective-C selector

Xcode 6.3 beta2で動作するようにこれを修正するにはどうすればよいですか?

編集:私も試しました:

  override func setSelected(selected: Bool) { 
    super.selected = selected
    // do something
 }

これはエラーにつながります:

メソッドは、そのスーパークラスのメソッドをオーバーライドしません

16
confile

selectedプロパティが設定された後、追加の機能を実行したい場合は、オーバーライドしてプロパティオブザーバーを追加できます。

override var selected: Bool {
    didSet {
        if self.selected {
            // do something
        }
    }
}

Swift 5:の回答を更新しました

override var isSelected: Bool {
    didSet {
        if self.isSelected {
            // do something
        }
    }
}

selectedの以前の値が何であったかを気にする場合は、oldValueを介してアクセスできます。

didSet {
    if self.selected == oldValue {
        return
    }
    // do something
}

Swift 5:の回答を更新しました

didSet {
    if self.isSelected == oldValue {
        return
    }
    // do something
}

また、値が変更される直前に何かを行う必要がある場合は、willSetも使用できることを忘れないでください。


それぞれがwillSetおよびdidSetプロパティオブザーバーに独自のものを追加するクラスの大きな階層があるとどうなるか興味があったので、次のテストを作成しました。

class ClassA {
    var _foo: Int = 0
    var foo: Int {
        set(newValue) {
            println("Class A setting foo")
            self._foo = newValue
        }
        get {
            return self._foo
        }
    }
}

class ClassB: ClassA {
    override var foo: Int {
        willSet {
            println("Class B will set foo")
        }
        didSet {
            println("Class B did set foo")
        }
    }
}

class ClassC: ClassB {
    override var foo: Int {
        willSet {
            println("Class C will set foo")
        }
        didSet {
            println("Class C did set foo")
        }
    }
}

ここで、ClassCのオブジェクトを作成し、そのfooプロパティを設定すると次のようになります。

var c: ClassC = ClassC()  
c.foo = 42

次の出力が得られます。

Class C will set foo
Class B will set foo
Class A setting foo
Class B did set foo
Class C did set foo

したがって、これからいくつかのことに注意することが重要です...

  • 子クラスのwillSetbeforeその親のwillSetと呼ばれます。
  • 子クラスのdidSetafterその親のdidSetと呼ばれます。
  • プロパティオブザーバーを追加するためのオーバーライドの作成しません親クラスのプロパティオブザーバーを置き換えます。

最初の2つのポイントは少し意味があります。そして実際には、これはプロパティオブザーバーをはるかに魅力的にします。事実上、Swiftは、適切な方法で階層を上下に移動させ、2つの別々のメソッドにうまく分割します。Swiftは、私たちを防ぎます(親クラスのプロパティをオーバーライドすることはできませんが、そのプロパティへの変更を観察することもできます。これは、Objective-Cのアプローチよりもはるかに優れています。

しかし、3番目のポイントはおそらく最も重要です。注意してください。didSetwillSetのコードの大規模な階層に簡単に行き詰まり、プロパティの値を設定するという非常に迅速なプロセスが遅くなる可能性があります。

42
nhgrif