Swift extension of a class ONLY when it conforms to a specific protocol
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 }}
Well, thus far I've found no truly satisfactory way of doing it, but I decided to post what I ended up doing for this particular problem.In a nutshell, the solution goes like this (using the original example code):
protocol MyProtocol{ func protocolFunction() { //do cool stuff... }}extension UIViewController //------->simple extension on UIViewController directly{ 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) //------->only run when self conforms to MyProtocol if let protocolConformingSelf = self as? MyProtocol { //invoke APIs from protocolConformingSelf.protocolFunction() // MyProtocol APIs let viewLoaded = protocolConformingSelf.isViewLoaded // UIViewController APIs } }}
Drawbacks:
- Not "the Swift way" of doing things
- The swizzling method will be invoked and take effect on ALL
UIViewControllers
, even though we validate for only those that conform to theMyProtocol
protocol to run the sensitive lines of code.
I very much hope it helps anyone else out there facing a similar situation =)