Подтвердить что ты не робот

Swift - как я могу переопределить метод расширения в конкретном подклассе

У меня есть расширение на 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
}
4b9b3361

Ответ 1

Как отмечают другие, 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 использует только динамическую отправку для методов, объявленных в исходный протокол, а не для методов, объявленных в расширениях протокола. Я предполагаю, что то же самое относится и к расширениям классов.

Ответ 2

Похоже, вы можете переопределить свойство для свойства 2-го суперкласса. Например, вы можете получить доступ к свойству UIView, добавив расширение UILabel, чтобы переопределить свойство frame в UIView. Этот образец работает для меня в Xcode 6.3.2

extension UILabel {

     override public var frame: CGRect {

         didSet {
             println("\(frame)")
        }
     }
}

Ответ 3

Я думаю, вы забыли переопределить свойство суперкласса в вашем подклассе:

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