19

プロトコルを実装する UIView の拡張機能があります

protocol SomeProtocol {
  var property : Int
}
    extension UIView : SomeProtocol {
      var property : Int {
        get {
          return 0
        }
        set {
          // do nothing
        }
      }
    }

具体的なサブクラスで、この拡張メソッドをオーバーライドしたい:

class Subclass : UIView, SomeProtocol {
  var _property : Int = 1
  var property : Int {
    get { return _property}
    set(val) {_property = val}
  }
}

ブレークポイントを設定すると、具体的なサブクラス メソッドではなく、拡張メソッドが呼び出されることがわかります。

var subclassObject = Subclass()

someObject.doSomethingWithConcreteSubclassObject(subclassObject)

// other code;

fun doSomethingWithConcreteSuclassObject(object : UIView) {
  var value = object.property // always goes to extension class get/set
}
4

6 に答える 6

17

他の人が指摘しているように、Swift では (まだ) クラス拡張で宣言されたメソッドをオーバーライドすることはできません。ただし、いつかSwiftでこれらのメソッドをオーバーライドできるようになったとしても、希望する動作が得られるかどうかはわかりません。

Swift がプロトコルとプロトコル拡張をどのように扱うかを検討してください。いくつかのメタ構文変数名を出力するプロトコルが与えられた場合:

protocol Metasyntactic {
    func foo() -> String
    func bar() -> String
}

デフォルトの実装を提供する拡張機能:

extension Metasyntactic {
    func foo() -> String {
        return "foo"
    }

    func bar() -> String {
        return "bar"
    }
}

そして、プロトコルに準拠するクラス:

class FooBar : Metasyntactic {
    func foo() -> String {
        return "FOO"
    }

    func bar() -> String {
        return "BAR"
    }
}

Swift は、動的ディスパッチを使用して、コンパイラによって推論された型ではなく、各変数のランタイム型foo()bar()基づいて適切な実装を呼び出します。

let a = FooBar()
a.foo()  // Prints "FOO"
a.bar()  // Prints "BAR"

let b: Metasyntactic = FooBar()
b.foo()  // Prints "FOO"
b.bar()  // Prints "BAR"

ただし、プロトコルをさらに拡張して新しいメソッドを追加すると、次のようになります。

extension Metasyntactic {
    func baz() -> String {
        return "baz"
    }
}

そして、プロトコルに準拠するクラスで新しいメソッドをオーバーライドすると、次のようになります。

class FooBarBaz : Metasyntactic {
    func foo() -> String {
        return "FOO"
    }

    func bar() -> String {
        return "BAR"
    }

    func baz() -> String {
        return "BAZ"
    }
}

Swift は、静的ディスパッチbaz()を使用して、コンパイラによって推論された型に基づいての適切な実装を呼び出すようになりました。

let a = FooBarBaz()
a.baz()  // Prints "BAZ"

let b: Metasyntactic = FooBarBaz()
b.baz()  // Prints "baz"

Alexandros Salazar は、この動作を詳細に説明した素晴らしいブログ投稿を持っていますが、Swift は元のプロトコルで宣言されたメソッドに対してのみ動的ディスパッチを使用し、プロトコル拡張で宣言されたメソッドに対しては使用しないと言えば十分です。クラス拡張についても同じことが言えると思います。

于 2016-10-09T06:31:41.857 に答える
3

私はこの質問が少し前に尋ねられたことを知っています。しかし、これはより簡単な方法を探している人にとっては便利です。拡張メソッドをオーバーライドする方法があります。私はそれが少しハックであることを知っていますが、それは美しく仕事をします。

でプロトコルを宣言すると@objc

@objc protocol MethodOverridable {
   func overrideMe()
}

拡張中

extension MainClass: MethodOverridable {
     func overrideMe() {
        print("Something useful")
     } 
}

サブクラス- サブクラスでオーバーライドできます。それは魔法のように機能します。まあ、@objcそれを追加するとあなたprotocol to Objective-CとそのRuntime. これにより、サブクラスがオーバーライドできます。

 class SubClass: MainClass {
     override func overrideMe() {
          print("Something more useful")
      }  
  }
于 2018-02-23T14:59:33.927 に答える
1

スイフト5

class Class
{
    @objc dynamic func make() { print("make from class") }
}

class SubClass: Class {}

extension SubClass {
    override func make() {
        print("override")
    }
}
于 2021-08-09T18:28:24.617 に答える
0

2番目のスーパークラスプロパティのプロパティをオーバーライドできるようです。たとえば、のオーバーライドしたいプロパティUIViewを拡張することで、プロパティにアクセスできます。このサンプルは、Xcode 6.3.2 で動作しますUILabelframeUIView

extension UILabel {

     override public var frame: CGRect {

         didSet {
             println("\(frame)")
        }
     }
}
于 2015-07-23T07:57:12.263 に答える
-3

サブクラスのスーパークラス プロパティをオーバーライドするのを忘れたと思います:

class Subclass : UIView {
    var _property : Int = 1
    override var property : Int {
        get { return _property}
        set(val) {_property = val}
    }
}
于 2015-04-27T10:28:43.583 に答える