Search code examples
iosswiftuiviewcontrollerdelegation

How to encapsulate an UIViewController (like UIAlertController) in Swift?


I have a ViewController in my Storyboard which works like an alert (with a title, a message, and two buttons).

I would like to encapsulate it to be able to use it anywhere in my code, like this :

let alert = CustomAlertViewController(title: "Test", message: "message de test.", view: self.view, delegate: self)
self.present(alert, animated: false, completion: nil)

My problem is that the IBOutlets are not initialised...

My CustomAlertViewController :

public protocol CustomAlertProtocol {
    func alertAccepted()
}

class CustomAlertViewController: UIViewController {

    var delegate :CustomAlertProtocol? = nil
    var parentView :UIView?
    var blurScreenshot :SABlurImageView?

    var alertTitle :String? = nil
    var alertMessage :String? = nil

    @IBOutlet weak var oAlertView: UIView!
    @IBOutlet weak var oAlertTitle: UILabel!
    @IBOutlet weak var oAlertMessage: UILabel!


    //MARK: - Main

    public convenience init(title: String?, message: String?, view: UIView, delegate: CustomAlertProtocol) {
        self.init()
        self.alertTitle = title
        self.alertMessage = message
        self.delegate = delegate
        self.parentView = view
    }

    override func viewDidLoad() {
        oAlertTitle.text = self.alertTitle
        oAlertMessage.text = self.alertMessage
    }

    @IBAction func onAcceptButtonPressed(_ sender: AnyObject) {
        delegate?.alertAccepted()
    }
}

Solution

  • Set the Custom Class property of your View Controller to CustomAlertViewController
    and Storyboard ID to whatever you want - e.g. CustomAlertViewControllerIdentifier in the Identity Inspector of the InterfaceBuilder.

    And then instantiate it like following:

    let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
    
    guard let vc = storyboard.instantiateViewControllerWithIdentifier("CustomAlertViewControllerIdentifier") as? CustomAlertViewController else {
        return
    }
    

    edit:

    You can then put that code in a class function like:

    extension CustomAlertViewController {
        class func instantiateFromStoryboard(title: String?, message: String?, view: UIView, delegate: CustomAlertProtocol) -> CustomAlertViewController {
            let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
            let vc = storyboard.instantiateViewControllerWithIdentifier("CustomAlertViewControllerIdentifier") as! CustomAlertViewController
    
            vc.title = title
            vc.message = message
            vc.view = view
            vc.delegate = delegate
    
            return vc
        }
    }
    

    and then use like:

    let myCustomAlertViewController = CustomAlertViewController.instantiateFromStoryboard(title: "bla", ...)