How to show an alert from another class in Swift?

2019-03-11 10:00发布

I have a main class, AddFriendsController, that runs the following line of code:

ErrorReporting.showMessage("Error", msg: "Could not add student to storage.")

I then have this ErrorReporting.swift file:

import Foundation

class ErrorReporting {
    func showMessage(title: String, msg: String) {
        let alert = UIAlertController(title: title, message: msg, preferredStyle: UIAlertControllerStyle.Alert)
        alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
        self.presentViewController(alert, animated: true, completion: nil)
    }
}

Obviously, self wouldn't work here, and is giving me an error. How can I refer to the currently open view controller (i.e. AddFriendsController in this circumstance), as I am wishing to use this same method in many different swift files?

Thanks.

3条回答
干净又极端
2楼-- · 2019-03-11 10:47

Actually, in my opinion the view controller presenting operation should be done on the UIViewController instance, not in a model class.

A simple workaround for it is to pass the UIViewController instance as a parameter

class ErrorReporting {
    func showMessage(title: String, msg: String, `on` controller: UIViewController) {
        let alert = UIAlertController(title: title, message: msg, preferredStyle: UIAlertControllerStyle.Alert)
        alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
        controller.presentViewController(alert, animated: true, completion: nil)
    }
}

And call it like below

ErrorReporting.showMessage("Error", msg: "Could not add student to storage.", on: self)
查看更多
爷、活的狠高调
3楼-- · 2019-03-11 10:51

You can create extension method for UIApplication (for example) which will return your topViewController:

extension UIApplication {

    static func topViewController(base: UIViewController? = UIApplication.sharedApplication().delegate?.window??.rootViewController) -> UIViewController? {
        if let nav = base as? UINavigationController {
            return topViewController(nav.visibleViewController)
        }
        if let tab = base as? UITabBarController, selected = tab.selectedViewController {
            return topViewController(selected)
        }
        if let presented = base?.presentedViewController {
            return topViewController(presented)
        }

        return base
    }
}

And then your class will look like this:

class ErrorReporting {

    static func showMessage(title: String, msg: String) {
        let alert = UIAlertController(title: title, message: msg, preferredStyle: UIAlertControllerStyle.Alert)
        alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil))
        UIApplication.topViewController()?.presentViewController(alert, animated: true, completion: nil)
    }
}

Method need to be static to be able to call it as ErrorReporting.showMessage.

查看更多
男人必须洒脱
4楼-- · 2019-03-11 10:57

Swift 3 version of Maksym Musiienko's answer would be the following:

extension UIApplication {

    static func topViewController(base: UIViewController? = UIApplication.shared.delegate?.window??.rootViewController) -> UIViewController? {

        if let nav = base as? UINavigationController {
            return topViewController(base: nav.visibleViewController)
        }

        if let tab = base as? UITabBarController, let selected = tab.selectedViewController {
            return topViewController(base: selected)
        }

        if let presented = base?.presentedViewController {
            return topViewController(base: presented)
        }

        return base
    }
}
查看更多
登录 后发表回答