Swift 2 协议扩展未正确调用覆盖的方法
Swift 2 protocol extension not calling overridden method correctly
我已经 运行 遇到了使用 Swift 2 协议扩展和默认实现的问题。基本要点是我提供了协议方法的默认实现,我在实现协议的 class 中重写了该方法。该协议扩展方法是从基 class 调用的,然后调用我在派生 class 中覆盖的方法。结果是重写的方法没有被调用。
我已尝试将问题提炼到尽可能小的范围内,这说明了下面的问题。
protocol CommonTrait: class {
func commonBehavior() -> String
}
extension CommonTrait {
func commonBehavior() -> String {
return "from protocol extension"
}
}
class CommonThing {
func say() -> String {
return "override this"
}
}
class ParentClass: CommonThing, CommonTrait {
override func say() -> String {
return commonBehavior()
}
}
class AnotherParentClass: CommonThing, CommonTrait {
override func say() -> String {
return commonBehavior()
}
}
class ChildClass: ParentClass {
override func say() -> String {
return super.say()
// it works if it calls `commonBehavior` here and not call `super.say()`, but I don't want to do that as there are things in the base class I don't want to have to duplicate here.
}
func commonBehavior() -> String {
return "from child class"
}
}
let child = ChildClass()
child.say() // want to see "from child class" but it's "from protocol extension”
不幸的是,协议还没有这样的动态行为。
但是您可以(在 classes 的帮助下)通过在 ParentClass
中实现 commonBehavior()
并在 ChildClass
中覆盖它来做到这一点。您还需要 CommonThing
或另一个 class 来符合 CommonTrait
,这就是 ParentClass
:
的超级 class
class CommonThing: CommonTrait {
func say() -> String {
return "override this"
}
}
class ParentClass: CommonThing {
func commonBehavior() -> String {
// calling the protocol extension indirectly from the superclass
return (self as CommonThing).commonBehavior()
}
override func say() -> String {
// if called from ChildClass the overridden function gets called instead
return commonBehavior()
}
}
class AnotherParentClass: CommonThing {
override func say() -> String {
return commonBehavior()
}
}
class ChildClass: ParentClass {
override func say() -> String {
return super.say()
}
// explicitly override the function
override func commonBehavior() -> String {
return "from child class"
}
}
let parent = ParentClass()
parentClass.say() // "from protocol extension"
let child = ChildClass()
child.say() // "from child class"
由于这只是您问题的一个简短解决方案,我希望它适合您的项目。
为了简化我对 "Yet" 这个词在非特定错误中的含义的理解。我想通了,我似乎不能写一个带参数的函数,在覆盖扩展函数时,编译器会给我这样的错误,但是如果我写一个没有参数的简单函数,并进行自定义实现并调用它用我的覆盖 "simple function" 它有效:
import Foundation
import UIKit
extension UIViewController {
func slideInView(direction: Direction = Direction.LEFT, duration: CFTimeInterval = 0.5, closure:()->() ) {
let animation = CABasicAnimation(keyPath: "transform.translation.x")
animation.fromValue = self.view.bounds.width
animation.toValue = 0
animation.duration = 0.3
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = false
UIView.animateWithDuration(0.6, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: {
self.view!.layer.addAnimation(animation,forKey:nil);
}, completion: {(finished) -> () in
closure()
});
}
func slide() {
self.slideInView(.LEFT,duration: 0.66) {
print("Slide in Left Complete")
}
}
}
class OtherUIViewController: UIViewController {
override func slide() {
self.slideFromBottom(.BOTTOM,duration: 0.66) {
print("Slide in Bottom Complete")
}
}
func slideFromBottom(direction: Direction = Direction.BOTTOM, duration: CFTimeInterval = 0.5, closure:()->() ) {
let animation = CABasicAnimation(keyPath: "transform.translation.y")
animation.fromValue = self.view.bounds.height
animation.toValue = 0
animation.duration = 0.3
animation.fillMode = kCAFillModeForwards
animation.removedOnCompletion = false
UIView.animateWithDuration(0.6, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: {
self.view!.layer.addAnimation(animation,forKey:nil);
}, completion: {(finished) -> () in
closure()
});
}
}
那是Swift的行为。它可以是好是坏,取决于你的需要。 Swift 使用静态调度,所以在编译期间必须知道调用了哪个方法。有一些优点,通常也有一些缺点。要了解 Swift 目前如何工作,请参阅下一个非常简单的示例。对我来说,它看起来合乎逻辑......
protocol P {
func foo()->Void
}
extension P {
func foo()->Void {
print("protocol foo")
}
}
class A:P {
}
class B:A {
func foo() {
print("B foo")
}
}
class C:B {
}
class D: C {
// here the implementation must be overriden,
// due the indirect inheritance from B
override func foo() {
print("D foo")
}
}
let a = A() // a is A type
a.foo() // protocol foo
let b = B() // B is B type
b.foo() // B foo
let p:P = B() // p is protocol P
// compiler is not able to know, what i would like, the dynamicType of p
// can be everything, conforming to protocol P
p.foo() // protocol foo
(p as? A)?.foo() // protocol foo
// casting to B type, I decided, that p is B type
(p as? B)?.foo() // B foo
(p as? D)?.foo() // nothing is printed, becase the result of casting is nil
// here the types are known at compile time
let c = C()
c.foo() // B foo
let d = D()
d.foo() // D foo
let e:C = D()
e.foo() // D foo
我已经 运行 遇到了使用 Swift 2 协议扩展和默认实现的问题。基本要点是我提供了协议方法的默认实现,我在实现协议的 class 中重写了该方法。该协议扩展方法是从基 class 调用的,然后调用我在派生 class 中覆盖的方法。结果是重写的方法没有被调用。
我已尝试将问题提炼到尽可能小的范围内,这说明了下面的问题。
protocol CommonTrait: class {
func commonBehavior() -> String
}
extension CommonTrait {
func commonBehavior() -> String {
return "from protocol extension"
}
}
class CommonThing {
func say() -> String {
return "override this"
}
}
class ParentClass: CommonThing, CommonTrait {
override func say() -> String {
return commonBehavior()
}
}
class AnotherParentClass: CommonThing, CommonTrait {
override func say() -> String {
return commonBehavior()
}
}
class ChildClass: ParentClass {
override func say() -> String {
return super.say()
// it works if it calls `commonBehavior` here and not call `super.say()`, but I don't want to do that as there are things in the base class I don't want to have to duplicate here.
}
func commonBehavior() -> String {
return "from child class"
}
}
let child = ChildClass()
child.say() // want to see "from child class" but it's "from protocol extension”
不幸的是,协议还没有这样的动态行为。
但是您可以(在 classes 的帮助下)通过在 ParentClass
中实现 commonBehavior()
并在 ChildClass
中覆盖它来做到这一点。您还需要 CommonThing
或另一个 class 来符合 CommonTrait
,这就是 ParentClass
:
class CommonThing: CommonTrait {
func say() -> String {
return "override this"
}
}
class ParentClass: CommonThing {
func commonBehavior() -> String {
// calling the protocol extension indirectly from the superclass
return (self as CommonThing).commonBehavior()
}
override func say() -> String {
// if called from ChildClass the overridden function gets called instead
return commonBehavior()
}
}
class AnotherParentClass: CommonThing {
override func say() -> String {
return commonBehavior()
}
}
class ChildClass: ParentClass {
override func say() -> String {
return super.say()
}
// explicitly override the function
override func commonBehavior() -> String {
return "from child class"
}
}
let parent = ParentClass()
parentClass.say() // "from protocol extension"
let child = ChildClass()
child.say() // "from child class"
由于这只是您问题的一个简短解决方案,我希望它适合您的项目。
为了简化我对 "Yet" 这个词在非特定错误中的含义的理解。我想通了,我似乎不能写一个带参数的函数,在覆盖扩展函数时,编译器会给我这样的错误,但是如果我写一个没有参数的简单函数,并进行自定义实现并调用它用我的覆盖 "simple function" 它有效:
import Foundation
import UIKit
extension UIViewController {
func slideInView(direction: Direction = Direction.LEFT, duration: CFTimeInterval = 0.5, closure:()->() ) {
let animation = CABasicAnimation(keyPath: "transform.translation.x")
animation.fromValue = self.view.bounds.width
animation.toValue = 0
animation.duration = 0.3
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = false
UIView.animateWithDuration(0.6, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: {
self.view!.layer.addAnimation(animation,forKey:nil);
}, completion: {(finished) -> () in
closure()
});
}
func slide() {
self.slideInView(.LEFT,duration: 0.66) {
print("Slide in Left Complete")
}
}
}
class OtherUIViewController: UIViewController {
override func slide() {
self.slideFromBottom(.BOTTOM,duration: 0.66) {
print("Slide in Bottom Complete")
}
}
func slideFromBottom(direction: Direction = Direction.BOTTOM, duration: CFTimeInterval = 0.5, closure:()->() ) {
let animation = CABasicAnimation(keyPath: "transform.translation.y")
animation.fromValue = self.view.bounds.height
animation.toValue = 0
animation.duration = 0.3
animation.fillMode = kCAFillModeForwards
animation.removedOnCompletion = false
UIView.animateWithDuration(0.6, delay: 0.0, options: UIViewAnimationOptions.CurveEaseOut, animations: {
self.view!.layer.addAnimation(animation,forKey:nil);
}, completion: {(finished) -> () in
closure()
});
}
}
那是Swift的行为。它可以是好是坏,取决于你的需要。 Swift 使用静态调度,所以在编译期间必须知道调用了哪个方法。有一些优点,通常也有一些缺点。要了解 Swift 目前如何工作,请参阅下一个非常简单的示例。对我来说,它看起来合乎逻辑......
protocol P {
func foo()->Void
}
extension P {
func foo()->Void {
print("protocol foo")
}
}
class A:P {
}
class B:A {
func foo() {
print("B foo")
}
}
class C:B {
}
class D: C {
// here the implementation must be overriden,
// due the indirect inheritance from B
override func foo() {
print("D foo")
}
}
let a = A() // a is A type
a.foo() // protocol foo
let b = B() // B is B type
b.foo() // B foo
let p:P = B() // p is protocol P
// compiler is not able to know, what i would like, the dynamicType of p
// can be everything, conforming to protocol P
p.foo() // protocol foo
(p as? A)?.foo() // protocol foo
// casting to B type, I decided, that p is B type
(p as? B)?.foo() // B foo
(p as? D)?.foo() // nothing is printed, becase the result of casting is nil
// here the types are known at compile time
let c = C()
c.foo() // B foo
let d = D()
d.foo() // D foo
let e:C = D()
e.foo() // D foo