Swift Override Function in 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.

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.

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.

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

How to override swift protocol functions for subclasses (e.g. UILabel from UIView)

You can achieve that as below, You just need to expose aProtocol to Objective-c runtime for overriding its methods in the extension.

@objc protocol aProtocol {
typealias completionBlock = (_ finished:Bool)->()
func doSomething(completion: completionBlock)
}

extension UIView: aProtocol {
func doSomething(completion: (Bool) -> ()) {
print("Im an UIView")
}
}

extension UILabel {
override func doSomething(completion: (Bool) -> ()) {
// you can call super.doSomething(completion: completion)
print("im an UILabel")
}
}

extension UIImageView {
override func doSomething(completion: (Bool) -> ()) {
// you can call super.doSomething(completion: completion)
print("im an UIImageView")
}
}

Output:

Im an UIView
Im an UIView
im an UILabel
im an UIImageView

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")
}
}

How to force usage of protocol default extension override?

I tried a few things, and somehow this works:

Declare contains in the protocol, not in an extension, like this:

func contains<T>(_ e: T) -> Bool where T: Equatable, T == BagObject

If you do things like T == BagObject in a class, a compiler error will show up saying that this makes T redundant, but apparently this is okay in a protocol.

Then, implement the default implementation like this:

extension Bag {
func contains<T>(_ e: T) -> Bool where T: Equatable, T == BagObject {
print("Default implementation is called")
return false
}
}

Then, you can just implement the concrete implementation directly in the class, as a non-generic method.

class BagConcreteImplementation<BagObject> : Bag {
func contains(_ e: BagObject) -> Bool where BagObject : Equatable {
print("Concrete implementation is called")
return bag.contains(e)
}

var bag = Array<BagObject>()
func add(_ e: BagObject) { bag.append(e) }
}

Without changing the call site, the code would print:

Concrete implementation is called
Concrete implementation is called


Related Topics



Leave a reply



Submit