J'ai une extension sur UIView implémentant un protocole
protocol SomeProtocol {
var property : Int
}
extension UIView : SomeProtocol {
var property : Int {
get {
return 0
}
set {
// do nothing
}
}
}
dans une sous-classe concrète, je veux remplacer cette méthode d'extension:
class Subclass : UIView, SomeProtocol {
var _property : Int = 1
var property : Int {
get { return _property}
set(val) {_property = val}
}
}
Je définis des points d'arrêt et vois que la méthode d'extension est appelée et non la méthode concrète de sous-classe:
var subclassObject = Subclass()
someObject.doSomethingWithConcreteSubclassObject(subclassObject)
// other code;
fun doSomethingWithConcreteSuclassObject(object : UIView) {
var value = object.property // always goes to extension class get/set
}
Comme d'autres l'ont noté , Swift ne vous permet pas (encore) de remplacer une méthode déclarée dans une extension de classe. Cependant, je ne sais pas si vous obtiendrez le comportement souhaité, même si/quand Swift vous permettra un jour de remplacer ces méthodes.
Considérez comment Swift traite les protocoles et les extensions de protocole. Étant donné un protocole pour imprimer certains noms de variables métasyntaxiques:
protocol Metasyntactic {
func foo() -> String
func bar() -> String
}
Une extension pour fournir des implémentations par défaut:
extension Metasyntactic {
func foo() -> String {
return "foo"
}
func bar() -> String {
return "bar"
}
}
Et une classe conforme au protocole:
class FooBar : Metasyntactic {
func foo() -> String {
return "FOO"
}
func bar() -> String {
return "BAR"
}
}
Swift utilisera dynamic dispatch pour appeler les implémentations appropriées de foo()
et bar()
en fonction du type runtime de chaque variable plutôt que du type induit par le compilateur:
let a = FooBar()
a.foo() // Prints "FOO"
a.bar() // Prints "BAR"
let b: Metasyntactic = FooBar()
b.foo() // Prints "FOO"
b.bar() // Prints "BAR"
Cependant, si nous étendons le protocole pour ajouter une nouvelle méthode:
extension Metasyntactic {
func baz() -> String {
return "baz"
}
}
Et si nous remplaçons notre nouvelle méthode dans une classe conforme au protocole:
class FooBarBaz : Metasyntactic {
func foo() -> String {
return "FOO"
}
func bar() -> String {
return "BAR"
}
func baz() -> String {
return "BAZ"
}
}
Swift utilisera maintenant static dispatch pour appeler l'implémentation appropriée de baz()
en fonction du type induit par le compilateur:
let a = FooBarBaz()
a.baz() // Prints "BAZ"
let b: Metasyntactic = FooBarBaz()
b.baz() // Prints "baz"
Alexandros Salazar a un fantastique billet de blog expliquant ce comportement en profondeur , mais il suffit de dire que Swift n’utilise la répartition dynamique que pour les méthodes déclarées dans le protocole original, not pour les méthodes déclarées dans les extensions de protocole. J'imagine qu'il en irait de même pour les extensions de classe.
Je sais que cette question a été posée il y a un moment. Mais ce sera pratique pour quelqu'un qui cherche un moyen plus facile. Il existe un moyen de remplacer une méthode d'extension. Je sais son bit hacky mais il fait le travail magnifiquement.
Si vous déclarez votre protocole avec @objc
@objc protocol MethodOverridable {
func overrideMe()
}
En extension
extension MainClass: MethodOverridable {
func overrideMe() {
print("Something useful")
}
}
Sous-classe - Vous pouvez le remplacer dans votre sous-classe. Cela fonctionne comme une magie. Eh bien, pas vraiment lorsque vous ajoutez @objc
, cela expose votre protocol to Objective-C
et sa Runtime
. Cela permet à votre sous-classe de remplacer.
class SubClass: MainClass {
override func overrideMe() {
print("Something more useful")
}
}
Il semble que vous puissiez remplacer la propriété pour la propriété 2nd super class. Par exemple, vous pouvez accéder à la propriété UIView
en faisant en sorte que UILabel
souhaite remplacer la propriété frame
de UIView
. Cet exemple fonctionne pour moi dans Xcode 6.3.2
extension UILabel {
override public var frame: CGRect {
didSet {
println("\(frame)")
}
}
}