Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What's the mechanics behind extension's methods overriding with '@objc' attribute?

Tags:

swift

Kind of nerd question. It's unclear to me, what exactly makes this code works:

class Shape { }

extension Shape {
    @objc func redraw() {
        print("from ext")
    }
}

class Circle: Shape { }

class Line: Shape {
    override func redraw() { // Compiler error: Declarations from extensions cannot be overridden yet
        print("from subclass")
    }
}

let line = Line()
let shape:Shape = line
let circle = Circle()

line.redraw() //from subclass
circle.redraw() //from ext
shape.redraw() //from subclass

If I omit @objc keyword in extension, the code won't compile - it's expected behaviour since methods in extension use static method dispatch -> cannot be overridden. But why adding @objc makes it work? According to documentation and most articles, all is @objc doing is making things visible to Objective-c runtime. To change method dispatch type there is a special keyword - dynamic. But seems it is not necessary here!

Help me figure out, why is adding @objc (and omitting dynamic) makes such things possible.

like image 658
surfrider Avatar asked Feb 24 '19 13:02

surfrider


People also ask

Can we override method in extension?

Extension methods cannot be overridden the way classes and instance methods are. They are overridden by a slight trick in how the compiler selects which extension method to use by using "closeness" of the method to the caller via namespaces.

Can we override method in extension Swift?

If a protocol defines a method, and provides a default implementation in an extension, a class can override that method, and the override will be called for any reference to the instance, even if the reference's type is declared as the protocol.

How do you override a function in Swift?

We use the override keyword to declare method overriding. For example, class Vehicle { func displayInfo(){ ... } } class Car: Vehicle { // override method override func displayInfo() { ... } }

What is @nonobjc?

The nonobjc attribute tells the compiler to make the declaration unavailable in Objective-C code, even though it's possible to represent it in Objective-C. Applying this attribute to an extension has the same effect as applying it to every member of that extension that isn't explicitly marked with the objc attribute.


1 Answers

Extensions,

as the name already says, are supposed to extend/add/include methods to an existing implementation, making them one of the most beautiful things about Objective-C, and now Swift, since you can add code to a class or framework you do not own. Therefore, it makes sense that you’re not supposed to “replace” code in extensions, conceptually speaking.

That’s why the compiler complains when you try to do it.

Also Check out this answer.

however this seems to be a support issue too, as swift compiler simply throw this error:

overriding non-@objc declarations from extensions is not supported.

According to Apple,

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

But that is not the case, as we are overriding from the extension not vice versa, which takes us back to the declaration of extension.

Extensions add new functionality to an existing class, structure, enumeration, or protocol type. This includes the ability to extend types for which you do not have access to the original source code (known as retroactive modeling). Extensions are similar to categories in Objective-C. (Unlike Objective-C categories, Swift extensions do not have names.) Here.

Going back to the legacy topic swift compiler vs Objc compiler,

Dynamic dispatch vs. Static dispatch .

And there is no official documentation from apple on why this is not supported from the swift compiler or if they have any future plans to fix this or consider it an issue at all.

However, there’s no such thing as Swift dynamic dispatch; we only have the Objective-C runtime’s dynamic dispatch. That means you can’t have just dynamic and you must write @objc dynamic. So this is effectively the same situation as before, just made explicit.

And here is a great article talking about this topic deeply.

like image 52
Mohmmad S Avatar answered Nov 13 '22 20:11

Mohmmad S