Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Swift extension of a class ONLY when it conforms to a specific protocol

Tags:

Hi there =) I was just faced with a design problem where I need to (essentially) do the following:

I want to inject a bit of code on viewWillAppear: of any UIViewController subclass that conforms to a protocol MyProtocol. Explained in code:

protocol MyProtocol {     func protocolFunction() {         //do cool stuff...     } }  extension UIViewController where Self: MyProtocol //<-----compilation error {     public override class func initialize()     {         //swizzling stuff switching viewWillAppear(_: Bool) with xxx_viewWillAppear(animated: Bool)     }      //  MARK: - Swizzling      func xxx_viewWillAppear(animated: Bool)     {         self.xxx_viewWillAppear(animated)          //invoke APIs from           self.protocolFunction() // MyProtocol APIs         let viewLoaded = self.isViewLoaded // UIViewController APIs      } } 

The main issue here is that I need to 2 two things in the UIVIewController extension:

  1. Invoke both MyProtocol and UIViewController API's
  2. Override UIViewController method initialize() in order to be able to swizzle viewWillAppear:

These 2 capabilities seem incompatible (as of Swift 3) because:

  1. We can't extend classes with conditions (i.e extension UIViewController where Self: MyProtocol)
  2. if we instead extend the protocol, we CAN add conditions extension MyProtocol where Self: UIViewController but we CAN'T override methods from a class in a protocol extension, meaning we can't public override class func initialize() which is needed for swizzling.

So I was wondering if there's somebody out there who can offer a Swifty solution to this problem I'm facing? =)

Thanks in advance!!

like image 233
Robertibiris Avatar asked Nov 17 '16 12:11

Robertibiris


People also ask

What kind of properties can a Swift extension have?

Computed Property In Extension However, Swift lets us add computed properties to an extension. For example, extension Circle { // computed property var area: Double { ... } } Here, area is a computed property defined in the extension body.

What is protocol and protocol extension in Swift?

Protocols let you describe what methods something should have, but don't provide the code inside. Extensions let you provide the code inside your methods, but only affect one data type – you can't add the method to lots of types at the same time.

What's the difference between a protocol and a class in Swift?

You can create objects from classes, whereas protocols are just type definitions. Try to think of protocols as being abstract definitions, whereas classes and structs are real things you can create. SPONSORED Want to explore your Swift skill outside of the Apple world?


1 Answers

You were near the solution. Just need to make it other way around. Extend protocol only if its part of UIViewController.

protocol MyProtocol {   func protocolFunction() {     //do cool stuff...   } }  extension MyProtocol where Self: UIViewController {   public override class func initialize()   {     //swizzling stuff switching viewWillAppear(_: Bool) with xxx_viewWillAppear(animated: Bool)   }    //  MARK: - Swizzling    func xxx_viewWillAppear(animated: Bool)   {     self.xxx_viewWillAppear(animated)      //invoke APIs from       self.protocolFunction() // MyProtocol APIs     let viewLoaded = self.isViewLoaded // UIViewController APIs   } } 
like image 144
Klemen Avatar answered Oct 11 '22 04:10

Klemen