簡體   English   中英

Swift調度到子類擴展中的重寫方法

[英]Swift dispatch to overridden methods in subclass extensions

在某些情況下,擴展中的重寫方法簽名似乎會產生不可預測的結果。 以下示例演示了具有類似模式的兩種不同結果。

class A: UIViewController {
    func doThing() {
        print("dothing super class")
    }

    override func viewDidLoad() {
        print("viewdidload superclass")
        super.viewDidLoad()
    }
}

class B: A { }

extension B {
    override func doThing() {
        print("dothing sub class")
        super.doThing()
    }

    override func viewDidLoad() {
        print("viewdidload subclass")
        super.viewDidLoad()
    }
}

let a: A = B()
a.doThing()

let vc: UIViewController = B()
vc.viewDidLoad()

這打印:

dothing super class
viewdidload subclass
viewdidload superclass

你可以看到它在轉換為A時跳過了BdoThing實現,但是在轉換為UIViewController時包含了viewDidLoad兩種實現。 這是預期的行為嗎? 如果是這樣,原因是什么?

ENV:Xcode 7.3,游樂場

令人驚訝的是,編譯器允許擴展中的覆蓋。 編譯:

class A {
    func doThing() {
        print("dothing super class")
    }
}
class B: A {
}
extension B {
    override func doThing() { // error: declarations in extensions cannot override yet
        print("dothing sub class")
        super.doThing()
    }
}

在您的示例中,似乎編譯器為您提供了一個傳遞,因為A派生自NSObject - 可能是為了允許此類與Objective-C進行交互。 確實編譯:

class A : NSObject {
    func doThing() {
        print("dothing super class")
    }
}
class B: A {
}
extension B {
    override func doThing() {
        print("dothing sub class")
        super.doThing()
    }
}

我的猜測是,你被允許做這個覆蓋的事實本身可能是一個錯誤。 文檔說:

擴展可以為類型添加新功能,但它們不能覆蓋現有功能。

並且覆蓋無法列為擴展可以做的事情之一。 所以它看起來像這應該編譯。 但是,正如我之前所說的那樣,也許這是有意與Objective-C兼容的。 無論哪種方式,我們正在探索一個邊緣情況,你已經很好地引出了它的邊緣。

特別是,前面的代碼仍然不會導致動態調度變得可操作。 這就是為什么你要么必須像doThing那樣將doThing聲明為dynamic ,要么將它放在實際的類而不是擴展中 - 如果你想要多態運行的話。 因此,這可以按照您的預期方式工作:

class A : NSObject {
    dynamic func doThing() {
        print("dothing super class")
    }
}
class B: A {
}
extension B {
    override func doThing() {
        print("dothing sub class")
        super.doThing()
    }
}

這樣做:

class A : NSObject {
    func doThing() {
        print("dothing super class")
    }
}
class B: A {
    override func doThing() {
        print("dothing sub class")
        super.doThing()
    }
}

我的結論是:非常好的例子; 將其作為可能的錯誤提交給Apple; 並且不要那樣做。 在課堂上重寫,而不是在擴展中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM