John Hass John Hass - 3 months ago 23
iOS Question

Can extension replace delegation in swift?

I am learning delegation in swift. This paragraph uses example to explain how delegation works.


In this simple example, I want to ensure that my app’s root view
controller, a UINavigationController, doesn’t permit the app to rotate
— the app should appear only in portrait orientation when this view
controller is in charge. But UINavigation‐ Controller isn’t my class;
it belongs to Cocoa. My own class is a different view controller, a
UIViewController subclass, which acts as the UINavigationController’s
child. How can the child tell the parent how to rotate? Well,
UINavigationController has a delegate property, typed as
UINavigationControllerDelegate (a protocol). It promises to send this
delegate the navigationControllerSupportedInterfaceOrientations
message when it needs to know how to rotate.


My question: Can we extend myOwnViewController to have method "navigationControllerSupportedInterfaceOrientations" to replace the delegation pattern to achieve the same goal?

Answer

You can extend myOwnViewController, tell extension to conform to UINavigationControllerDelegate protocol and implement method that you want, however this does not replace the delegation pattern. If your extension does not conform to this delegate's protocol, you won't be able to attach myOwnViewController as UINavigationController's delegate.

class MyController: UIViewController {
}

extension MyController: UINavigationControllerDelegate {
    override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        return .Portrait
    }
}
let navigationController = UINavigationController()
let controller = MyController()
navigationController.delegate = controller

Same result can be achieved by telling MyController class to conform to UINavigationControllerDelegateprotocol.

class MyController: UIViewController, UINavigationControllerDelegate {

    override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask {
        return .Portrait
    }

}
let navigationController = UINavigationController()
let controller = MyController()
navigationController.delegate = controller

Those two examples result in MyController being the delegate for your UINavigationController. This can lead to having many responsibilities in one place. In order to split this responsibility, you can create another class that will be the delegate for your navigation controller.

class MyController: UIViewController {}

class NavigationDelegate: NSObject, UINavigationControllerDelegate {

    func navigationControllerSupportedInterfaceOrientations(navigationController: UINavigationController) -> UIInterfaceOrientationMask {
        return .Portrait
    }

}
let navigationController = UINavigationController()
let controller = MyController()
let navigationDelegate = NavigationDelegate()
navigationController.delegate = navigationDelegate

What is the difference? Imagine that you have implemented a complex logic for your supported orientation method and you find out that you don't use MyController any more, instead, you will use DifferentController. Since your orientation logic is in MyController, you would need to create it anyway. However, if your delegate logic is separated in NavigationDelegate class, you can use DifferentController without need of creating MyController class just for these delegate methods.