Overriding Methods in Swift Extensions

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.

Overriding a method in an extension, Swift

Dynamic modifier

You can do it using the dynamic modifier

@objc class Animal: NSObject {

@objc dynamic func saySomething() {
print("I am an Animal")
}

}

@objc class Dog: Animal { }

extension Dog {

override func saySomething() {
print("I am a Dog")
}

}

Dog().saySomething() // I am a Dog

Tested with Swift 5.1.3

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.

Swift overriding extension method

Just move the declaration of create into the actual class declaration. Everything else can stay the same:

protocol Creator {
func create()
}
class BaseClass {
func create() {
print("create")
}
}
extension BaseClass: Creator {
}
// and so on

The effect is precisely the same, but now override func create() is legal in your subclasses.

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 override function in extension

From the documentation:

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

The documentation lists carefully and precisely what an extension is allowed to do.

As to your question:

Is there anyway to override a function of a particular class

Yes, it's called subclassing.

Swift override protocol methods in sub classes

Use protocol extension with where clause. It works.
But I would not recommend you to have such things in your codebase.

class BaseViewController: UIViewController {

}

extension OptionsDelegate where Self: BaseViewController {
func handleSortAndFilter(opt: Options) {
print("Base class implementation")
}
}

extension BaseViewController: OptionsDelegate {

}

class InsipartionsViewController: BaseViewController {

}

extension OptionsDelegate where Self: InsipartionsViewController {
func handleSortAndFilter(opt: Options) {
print("Inspirations class implementation")
}
}

Override object method using Swift protocols and extensions

It works if you add the name() function also to MyHelloObject:

class MyHelloObject: Object, SayHelloProtocol {
override func printSomething() {
hello()
}

func name() -> String {
"Someone"
}
}

class MyHelloChildObject: MyHelloObject {
override func name() -> String {
"You"
}
}

How to override instance method from protocol extension in Swift?

The default implementations in the protocols are only called if the class that conforms to these protocols do not implement that method itself. The classes' methods override the default implementations of the protocols, not the other way around.

Typically, you'd do something like:

protocol MyProtocolA {
func speak()
}

protocol MyProtocolB {
func speak()
}

extension MyProtocolA {
func speak() {
print("A")
}
}

extension MyProtocolB {
func speak() {
print("B")
}
}

class SubA: MyProtocolA {}

class SubB: MyProtocolB {}

let suba = SubA()
suba.speak() // prints "A"

let subb = SubB()
subb.speak() // prints "B"

But if you do

class SubC: MyProtocolA {
func speak (){
print("C")
}
}

let subc = SubC()
subc.speak() // prints "C"

Frankly, as you look at this, the use of Base is entirely redundant in this example, so I've removed it. Clearly, if you need to subclass from Base for other reasons, feel free. But the key point is that protocol default implementations don't override the classes' implementation, but rather the other way around.



Related Topics



Leave a reply



Submit