How to Create an Alert in a Swift File Model That Works for Various View Controller

how to create an alert in a swift file model that works for various view controller

There's no reason that your Alert class should be extending UIViewController since your Alert class isn't a view controller.

What you should be doing is making your showAlert method a method of UIViewController via an extension.

Change:

class Alert : UIAlertController {

to:

extension UIAlertController {

Then when you want to show an alert from a view controller (such as your ViewController class, you simply call showAlert.

class ViewController: UIViewController {
func test() {
showAlert(alertTitle: "Opps", alertMessage: "less than 15", actionTitle: "OK")
}
}

How to create a reusable alert view used across different view controllers?

You need alert action to performing ok action.

You can modify your code by this

Here are the helper functions.

struct AlertView {
public static func showAlertBox(title: String, message: String, handler: ((UIAlertAction)->Void)?) -> UIAlertController {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .cancel, handler: handler))
return alert
}
}

extension UIAlertController {
func present(on viewController: UIViewController, completion: (() -> Void)? = nil) {
viewController.present(self, animated: true, completion: completion)
}
}

Usage

class ViewController: UIViewController {

@IBAction func submitPressed(_ sender: Any) {
AlertView.showAlertBox(title: "Hours Added", message: "Hours have been updated") { [weak self] action in
// Okay action code
}.present(on: self) { [weak self] in
self?.dismiss(animated: true, completion: nil)
self?.timeSubmitted = true
self?.performSegue(withIdentifier: "unwindToMyHours", sender: nil)
}
}
}
Note: self is dismissing so might be your alert is not presenting. You can present your alert on top most view controller. see this

create alert function in all view controllers - swift

What I would do is to create a 'generic' view controller that do the job and than inherit from it:

1. If you want to display alert each time view did appear:

class GenericViewController: UIViewController {

// MARK: - View lifecycle -

override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
if let notification = self.shouldDisplayAlertNotification() {
self.showNotification(notification)
}
}

// MARK: - Internal methods -

func shouldDisplayAlertNotification() -> AlertNotification? {
return nil
}

// MARK: - Private methods -

private func showNotification(_ alertNotification: AlertNotification) {
}

}

class MyController: GenericViewController {

override func shouldDisplayAlertNotification() -> AlertNotification? {
return AlertNotification(title: "Title", message: "Message")
}

}

Where AlertNotification is your custom model class:

class AlertNotification {
var title: String
var message: String

init(title: String, message: String) {
self.title = title
self.message = message
}
}

In this way, only VC that overrides shouldDisplayAlertNotificationwill display alert.

2. If you want to display alert on 'demand':

As suggested, extend UIViewController

extension UIViewController {
func showNotification(title: String, message: String) {
}
}

How to show an alert from another class in Swift?

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.

Swift Displaying Alerts best practices

I ended up creating an extension for UIViewController and creating the alert function there:

extension UIViewController {
func alert(message: String, title: String = "") {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
let OKAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alertController.addAction(OKAction)
self.present(alertController, animated: true, completion: nil)
}
}

How to use NSAlert Sheet Modal from a Utility class

It would be much easier to extend NSViewController and make showAlert an instance method of it. This way you would have access to the view controller's view.window property of the view controller which is calling this method. Note don't forget to call super when overriding viewDidAppear method. Note that your approach should work if you build and run your app (this is just an issue of running your app from Xcode) but be aware that your method might fail if your app is not active when executing that code. Using the view controller's view.window property is much safer:

extension NSViewController {
func showAlert() {
let alert = NSAlert()
alert.messageText = "Warning: This is an alert!"
alert.informativeText = "Something informative will be here!"
alert.addButton(withTitle: "Continue")
alert.addButton(withTitle: "Exit")
if let window = view.window {
alert.beginSheetModal(for: window) { modalResponse in
alert.window.close()
switch modalResponse.rawValue {
case 1001: // Exit
exit(0)
default: // Continue
return
}
}
}
}
}

Usage:

class ViewController: NSViewController {
override func viewDidAppear() {
super.viewDidAppear()
showAlert()
}
}

edit/update:

If you don't want to extend NSViewController the safest approach is to pass the window when calling your method:

class ViewController: NSViewController {  
let utility = UtilityController()
let dataController = DataController()
override func viewDidAppear() {
super.viewDidAppear()
dataController.fetchData(view.window)
}
}


class UtilityController: NSObject {
func showAlert(_ sender: NSWindow?) {
guard let sender = sender else { return }
let alert = NSAlert()
alert.messageText = "Warning: This is an alert!"
alert.informativeText = "Something informative will be here!"
alert.addButton(withTitle: "Continue")
alert.addButton(withTitle: "Exit")
alert.beginSheetModal(for: sender) { modalResponse in
alert.window.close()
switch modalResponse.rawValue {
case 1001:
exit(0)
default:
return
}
}
}
}


import Cocoa

class DataController: NSObject {
let utility = UtilityController()
func fetchData(_ sender: NSWindow?) {
utility.showAlert(sender)
}
}

How to create uialertcontroller in global swift

self.window would mean that there's a window object in this class, and it's not the case.

You would need to use your let window : UIWindow? with window?.presentViewController(alert, animated: true, completion: nil), but this won't help, since this window does not actually represent any existing window, and it's not a view controller anyway.

So I suggest you pass the actual view controller you'll be using to the method:

static func showAlertMessage(vc: UIViewController, titleStr:String, messageStr:String) -> Void {
let alert = UIAlertController(title: titleStr, message: messageStr, preferredStyle: UIAlertControllerStyle.Alert);
vc.presentViewController(alert, animated: true, completion: nil)
}

and you call it from a class where a UIViewController object is available.

How to create my own UIAlertController in Swift 5?

An alert is nothing but a presented view controller. So make your own view controller and call present. It's as simple as that.



Related Topics



Leave a reply



Submit