Micah Montoya
Micah Montoya

Reputation: 767

Call function in UIViewController from an extension

I have a UIViewController which loads up some json data from the server. If the server is down or the user has data turned off I throw up an alert telling the user such. This is done using a UIAlertController. This works great. So I put this into an extension since it is used by all UIViewControllers which need data. Now the UIAlertController has an action set as well

Alert code

extension UIViewController {    
func connectionLost(){
    var message = "Your device has lost connection to the server. Check that you have a valid internet connection and then retry."

    let alertController = UIAlertController( title: "Connection Lost",
                                             message: message,
                                             preferredStyle: .alert)
    let retryAction = UIAlertAction(title:"Retry", style: .default, handler: {
        action in

        //call function in the viewcontroller that raised this alert to reload the data
    })
    alertController.addAction(retryAction)
    self.present(alertController, animated: true, completion: nil)
}
}

When the user taps the retry button I want to call a function in the uiviewcontroller that raised the alert.

I tried creating a delegate in the extension but struggled with getting it wired up like you do in a class. What sort of approaches are there to call a function from an extension in the viewcontroller that raised the alert?

Upvotes: 1

Views: 566

Answers (2)

Santosh
Santosh

Reputation: 2914

Hope this makes sense.

class MyVC: UIViewController {

    func retry() {

    }

    func checkConnection() {
        connectionLost { (retry) -> (Void) in
            if retry {
                self.retry()
            }
        }
    }
}


extension UIViewController {
    func connectionLost(completion: @escaping (_ retry: Bool) -> (Void)) {
        let message = "Your device has lost connection to the server. Check that you have a valid internet connection and then retry."

        let alertController = UIAlertController( title: "Connection Lost",
                                             message: message,
                                             preferredStyle: .alert)
        let retryAction = UIAlertAction(title:"Retry", style: .default, handler: {
        action in
            completion(true)//may be 'false', you decide
        })
        alertController.addAction(retryAction)
        self.present(alertController, animated: true, completion: nil)
    }
}

Upvotes: 0

lubilis
lubilis

Reputation: 4160

You should create a BaseViewController and use Inheritance. It could be useful for other implementations too.

class BaseViewController: UIViewController {

    func onRetryClick() {
        // override to customize or write here the common behaviour
    }
}

class FirstViewController: BaseViewController {
    override func onRetryClick() {
        // do something specific for FirstViewController
    }
}

class SecondViewController: BaseViewController {
    override func onRetryClick() {
        // do something specific for SecondViewController
    }
}

class ThirdViewController: BaseViewController {
    // if you don't override this method, super class (BaseViewController) implementation will be executed
}

extension BaseViewController {    

    func connectionLost(){
        var message = "Your device has lost connection to the server. Check that you have a valid internet connection and then retry."

        let alertController = UIAlertController( title: "Connection Lost",
                                             message: message,
                                             preferredStyle: .alert)
        let retryAction = UIAlertAction(title:"Retry", style: .default, handler: { action in
            self.onRetryClick()
        })

        alertController.addAction(retryAction)
        self.present(alertController, animated: true, completion: nil)
    }
}

Upvotes: 2

Related Questions