问题
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