1

I need to post a notification on viewDidLoad of every one of my ViewControllers. I have a BaseViewController with a postNotification method, and it gets an enum as a parameter to identify the screen. It looks like this

class BaseViewController {

    func postNotification(for screen: ScreenName) {
        NotificationCenter.default.post(name: notification,
                                        object: nil,
                                        userInfo: ["ScreenName": screen])
    }
}

class AViewController: BaseViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        postNotification(for: screenA)
    }
}

class BViewController: BaseViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        postNotification(for: screenB)
    }
}

Suppose we need to add another view controller later in the future, such as CViewController. I want to force the developer of CViewController to call this postNotification method with screen enum.

What is the best practice to achieve this on Swift?

Edit

Thanks to Loren's suggestion, I added a protocol on my base class

typealias BaseController = BaseViewController & BaseProtocol

protocol BaseProtocol {
    var screenName: ScreenName { get }
}

This forces all my viewcontrollers to conform protocol and initialize screenName, but now I can't get it from my BaseViewController. If I can get child view controller's screenName property from BaseViewController, I would eliminate calling postNotification method on each child, and call it only on BaseViewController

mamba4ever
  • 2,662
  • 4
  • 28
  • 46
  • Does this link help (about 3/4 down)? https://stackoverflow.com/questions/24111356/swift-class-method-which-must-be-overridden-by-subclass/24481555 – Loren Rogers Oct 18 '19 at 00:55
  • Hey thanks! It kinda helped, but created another problem. I updated my question accordingly – mamba4ever Oct 18 '19 at 01:17

1 Answers1

0
class BaseViewController: UIViewController {

    var screenName: ScreenName!

    override func viewDidLoad() {
        super.viewDidLoad()
        if let screenName = self.screenName {
            self.postNotification(for: screenName)
        } else {
            fatalError("screenName must be instantiated")
        }
    }

    func postNotification(for screen: ScreenName) {
        NotificationCenter.default.post(name: notification,
                                        object: nil,
                                        userInfo: ["ScreenName": screen])
    }
}

class AViewController: BaseViewController {

    override func viewDidLoad() {
        self.screenName = screenA
        super.viewDidLoad()
    }
}

class BViewController: BaseViewController {

    override func viewDidLoad() {
        self.screenName = screenB
        super.viewDidLoad()
    }
}

Try this since you are using inheritance, have BaseViewController inherit UIViewController superclass, then create a screenName variable. In your childViewControllers instantiate the screenName before calling super.viewDidLoad(). You can use protocols like you mentioned to force the implementation of the variable, but it just seems like overkill for just one variable.

Alexander
  • 1,424
  • 18
  • 23
  • This doesn't solve my initial problem. Developer can add CViewController and forget to set screenName in your solution. I want to force (give compile time error) developer to change screenName. – mamba4ever Oct 18 '19 at 02:02
  • I added a fatalError() when safely unwrapping the screenName variable when calling `postNotification` in `viewDidLoad` of the `BaseViewController`. `super.viewDidLoad` will always be called – Alexander Oct 18 '19 at 02:06
  • Thanks for updating your answer, but this gives a Runtime error. I still believe there should be a solution that gives compile time error – mamba4ever Oct 18 '19 at 02:12