`Override` Protocol Extension Default Implementation in Swift

Muhammad Muizzsuddin
3 min readMar 20, 2019

--

Source: https://unsplash.com/photos/-liXI0tSqE0

You may want to read https://team.goodeggs.com/overriding-swift-protocol-extension-default-implementations-d005a4428bda

This is my next story after so long (may be four month) absent from writing in Medium so bear with me for not satisfiy you.

I’ve read people have problem when they come to make their Swift code more compact and follow Protocol Oriented Programming. Both can be achieved but also have some limitations.

Let me show you my context.

This code doesn’t compile!

In above code, I have a protocol X which I want to make UIView implement it. Then to implement X , UIView must provide implementation for method x() , we know it.

But let’s say we want to override the x() implementation in UIStackView which is UIView subclass. Here’s the problem comes. An extension can’t be overridden because the way Swift implement extension is using static dispatch which means its resolved at compile time.

Read https://www.raizlabs.com/dev/2016/12/swift-method-dispatch/

Ok, actually above code can be compiled using some tricks if it is your goal to make the code compile.

First, because the compiler stating that we can’t override non-objc declaration in extension, then we must make the method to be implemented to be an @objc method. Which this workaround make the method to be dynamic dispatch. Resolved at runtime!

This code using @objc compiles!

But wait! Does it run correctly?

It works!

Ahh, it works at runtime!

We happy, overriding extension in subclass can be achieved! But there’s limitation.

Using @objc means that your protocol requirement signature should compatible with @objc. What if you made a requirement which you depends on type which not compatible to @objc? Sure you can’t do much. The limitations is scary!

Let’s take a look to another approach.

Self Constrained Protocol Extension

Using this approach you don’t need to expose anything to @objc since this workaround is fully Swift. But let me give you a clue, this doesn’t work for dynamic dispatch. This compiles, but your code will have bug if you call the method hiding under its superclass type.

It compiles!

Yes, it compiles correctly. But does it works at runtime?

It doesn’t work.

As you can see in the Debug output. When we call x() in UIStackView that was hidden under UIView it doesn’t work as if we use @objc above. That because s resolved at compile time to call x() using implementation where Self: UIView .

Conclusion

If your implementation should be dispatched dynamically you must not use this override idea to works with protocol extension. You always have a chance to use @objc with its limitations or you can use constrained protocol extension with the fear of bug hidden in your client code. Be wise my friend.

PS: I’ve implemented @objc version in this library ViewDSL

--

--

Responses (1)