Declarations from extensions cannot be overridden yet in Swift 4

狂风中的少年 提交于 2021-02-18 20:12:46

问题


I have recently migrated my code to Swift 4. There is an issue that I am facing with extensions, i.e.:

Declarations from extensions cannot be overridden yet

I have already read multiple posts regrading this issue. But none of them entertains the scenario described below:

class BaseCell: UITableViewCell
{
    //Some code here...
}

extension BaseCell
{
    func isValid() -> String?
    {
        //Some code here...
    }
}

class SampleCell: BaseCell
{
    //Some code here...

    override func isValid() -> String? //ERROR..!!!
    {
        //Some code here...
    }
}

According to Apple,

Extensions can add new functionality to a type, but they cannot override existing functionality.

But in the above scenario, I am not overriding the method isValid() in extension. It is overridden in the SampleCell class definition itself. Still, it is giving the error.


回答1:


But in the above scenario, I am not overriding the method isValid() in an extension.

isValid gets declared in an extension.

The error pretty much says that if a function is declared this way, it cannot be overridden.

The statement is valid for both from an extension and in an extension.




回答2:


You can override declarations from extensions as long as you @objc the protocol. In Swift 4.2:

class BaseClass {}
class SubclassOfBaseClass: BaseClass {}

@objc protocol IsValidable {
    func isValid() -> Bool
}

extension BaseClass: IsValidable {
    func isValid() -> Bool { return false }
}

extension SubclassOfBaseClass {
    override func isValid() -> Bool { return !super.isValid() }
}

BaseClass().isValid()           // -> false
SubclassOfBaseClass().isValid() // -> true



回答3:


In Swift 3, you were able to override the function of extension if extension was of a class that is getting derived from Objective-C (http://blog.flaviocaetano.com/post/this-is-how-to-override-extension-methods/), but I guess its not possible now in Swift 4. You can ofcourse do something like this:

protocol Validity {
    func isValid() -> String?
}

class BaseCell: UITableViewCell, Validity {

}

extension Validity
{
    func isValid() -> String? {
        return "false"
    }
}

class SampleCell: BaseCell {

    func isValid() -> String? {
        return "true"
    }
}


let base = BaseCell()
base.isValid() // prints false

let sample = SampleCell()
sample.isValid() // prints true



回答4:


I think this is self-explanatory. declarations FROM extensions cannot be overridden yet

You are trying to override the function func isValid() -> String? which was declared within an extension of BaseCell, not the BaseCell class itself.

It is clearly saying that you can't override something that was declared inside an extension.

Hope it is helpful.




回答5:


I too had a huge legacy of Swift 3 code that used this old trick to achieve what I wanted, so when I moved to Swift 4 and started getting these errors, I was somewhat distressed. Fear not, there is a solution.

This error has to do with the way Swift 4 compiles classes and the new way it treats Objective-C classes and functions. Under Swift 3, if a class is derived from NSObject, then all the variables and functions in that class would use Objective-C's dynamic naming and lookup conventions. This approach inhibited Swift's ability to optimise the code and improve code performance and size.

To overcome these penalties, in Swift 4, only variables and functions explicitly tagged with @objc get the Objective-C treatment, everything else uses standard Swift conventions: hence the error.

Armed with this knowledge, the solution to your problem is to tag the functions in the extension you wish to be overridden as @objc, then in the child classes, override the function, but remember to include the @objc tag so your code will get called at runtime.

WARNING The is a little gotcha here: if you forget to include the @objc in the override, the compiler will not complain, but your code lacks the dynamic lookup, so never gets called at runtime.

So your code should look a bit like this:

class BaseCell: UITableViewCell {
    //Some code here...
}

extension BaseCell {
    @objc func isValid() -> String? {
        //Some code here...
    }
}

class SampleCell: BaseCell {
    //Some code here...

    @objc override func isValid() -> String? {
        //Some code here...
    }
}



回答6:


It is invalid in Swift, however not in Objective-C. So, if your method signature allows it (no objc forbidden constructs), you can declare it @objc func myMethod() and override it freely in Swift.



来源:https://stackoverflow.com/questions/46564557/declarations-from-extensions-cannot-be-overridden-yet-in-swift-4

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!