Can you override between extensions in Swift or not? (Compiler seems confused!)
It seems that overriding methods and properties in an extension works with the
current Swift (Swift 1.1/Xcode 6.1) only for Objective-C compatible
methods and properties.
If a class is derived from NSObject
then all its members are automatically available
in Objective-C (if possible, see below). So with
class A : NSObject { }
your example code compiles and works as expected. Your Code Data extension overrides
work because NSManagedObject
is a subclass of NSObject
.
Alternatively, you can use the @objc attribute for a method or property:
class A { }
class B : A { }
extension A
{
@objc var y : String { get { return "YinA" } }
}
extension B
{
@objc override var y : String { get { return "YinB" } }
}
Methods which are not representable in Objective-C cannot be marked with @objc
and cannot be overridden in a subclass extension. That applies for example to
methods having inout
parameters or parameters of an enum
type.
Declarations in extensions cannot override yet
The error message is pretty clear (despite the somewhat dubious grammar):
declarations from extensions cannot be overridden yet
You cannot override a function that is declared in an extension (The 'yet' implies that this may be possible in a future version of Swift).
If you want to be able to override extFunction
you must declare it in BaseViewController
itself, not in an extension.
Declarations from extensions cannot be overridden yet in Swift 4
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.
Overriding methods in Swift extensions
Extensions cannot/should not override.
It is not possible to override functionality (like properties or methods) in extensions as documented in Apple's Swift Guide.
Extensions can add new functionality to a type, but they cannot override existing functionality.
Swift Developer Guide
The compiler is allowing you to override in the extension for compatibility with Objective-C. But it's actually violating the language directive.
That just reminded me of Isaac Asimov's "Three Laws of Robotics" /p>
Extensions (syntactic sugar) define independent methods that receive their own arguments. The function that is called for i.e. layoutSubviews
depends on the context the compiler knows about when the code is compiled. UIView inherits from UIResponder which inherits from NSObject so the override in the extension is permitted but should not be.
So there's nothing wrong with grouping but you should override in the class not in the extension.
Directive Notes
You can only override
a superclass method i.e. load()
initialize()
in an extension of a subclass if the method is Objective-C compatible.
Therefore we can take a look at why it is allowing you to compile using layoutSubviews
.
All Swift apps execute inside the Objective-C runtime except for when using pure Swift-only frameworks which allow for a Swift-only runtime.
As we found out the Objective-C runtime generally calls two class main methods load()
and initialize()
automatically when initializing classes in your app’s processes.
Regarding the dynamic
modifier
From the Apple Developer Library (archive.org)
You can use the dynamic
modifier to require that access to members be dynamically dispatched through the Objective-C runtime.
When Swift APIs are imported by the Objective-C runtime, there are no guarantees of dynamic dispatch for properties, methods, subscripts, or initializers. The Swift compiler may still devirtualize or inline member access to optimize the performance of your code, bypassing the Objective-C runtime. /p>
So dynamic
can be applied to your layoutSubviews
-> UIView Class
since it’s represented by Objective-C and access to that member is always used using the Objective-C runtime.
That's why the compiler allowing you to use override
and dynamic
.
override does not work inside extension object in swift
The error is quite clear:
You have to move the overriding method from the extension
into the class
Or you have to mark the declaration in the base class with @objc
and @dynamic
class BaseTableViewCell : UITableViewCell {
@objc class dynamic var identifier : String { return "something" }
}
Can I override a Swift method that has been overridden by an extension?
Extensions can add new functionality to a type, but they cannot
override existing functionality.
Answer is here Swift override function in extension
Swift - How can I override an extension method in a concrete subclass
As others have noted, Swift does not (yet) allow you to override a method declared in a class extension. However, I'm not sure whether you'll ever get the behavior you want even if/when Swift someday allows you to override these methods.
Consider how Swift deals with protocols and protocol extensions. Given a protocol to print some metasyntactic variable names:
protocol Metasyntactic {
func foo() -> String
func bar() -> String
}
An extension to provide default implementations:
extension Metasyntactic {
func foo() -> String {
return "foo"
}
func bar() -> String {
return "bar"
}
}
And a class that conforms to the protocol:
class FooBar : Metasyntactic {
func foo() -> String {
return "FOO"
}
func bar() -> String {
return "BAR"
}
}
Swift will use dynamic dispatch to call the appropriate implementations of foo()
and bar()
based on each variable's runtime type rather than on the type inferred by the compiler:
let a = FooBar()
a.foo() // Prints "FOO"
a.bar() // Prints "BAR"
let b: Metasyntactic = FooBar()
b.foo() // Prints "FOO"
b.bar() // Prints "BAR"
If, however, we extend the protocol further to add a new method:
extension Metasyntactic {
func baz() -> String {
return "baz"
}
}
And if we override our new method in a class that conforms to the protocol:
class FooBarBaz : Metasyntactic {
func foo() -> String {
return "FOO"
}
func bar() -> String {
return "BAR"
}
func baz() -> String {
return "BAZ"
}
}
Swift will now use static dispatch to call the appropriate implementation of baz()
based on the type inferred by the compiler:
let a = FooBarBaz()
a.baz() // Prints "BAZ"
let b: Metasyntactic = FooBarBaz()
b.baz() // Prints "baz"
Alexandros Salazar has a fantastic blog post explaining this behavior in depth, but suffice it to say that Swift only uses dynamic dispatch for methods declared in the original protocol, not for methods declared in protocol extensions. I imagine the same would be true of class extensions, as well.
Related Topics
How to Document the Parameters of a Function'S Closure Parameter in Swift 3
Default Value For Optional Generic Parameter in Swift Function
Function with Datatask Returning a Value
What Are the Differences Between Throws and Rethrows in Swift
Simple Way to Read Local File Using Swift
How to Get the File Creation Date Using Url Resourcevalues Method in Swift 3
How to Cycle Through the Entire Alphabet with Swift While Assigning Values
How to Set a New Root View Controller
Swift: Extending Functionality of Print() Function
What's the Difference Between Using Aranchor to Insert a Node and Directly Insert a Node
Command Compileswiftsources Failed With a Nonzero Exit Code Xcode 10
Iboutlet and Ibaction in Swift
Why Use Required Initializers in Swift Classes
Swift - Unit Testing Private Variables and Methods
Expected to Decode Array<Any> But Found a Dictionary Instead
How May I Test the Equivalency of Enumeration Cases with Associated Values in Swift 4