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 shouldDisplayAlertNotification
will 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
How to Update iOS 14 Widget Background Color from the App
Modifing One Variable from Another View Controller Swift
How to Download and View Images from the New Firebase Storage
Ios-Charts How to Put Uiimage Beside a Point
Ksecattrkeytypeec Causing Encryptmessagewithpublickey() to Fail
Passing Data Between Views in One Viewcontroller in Swift
iOS 10.3 - How to Change App Icon Programmatically
Uiimageview .Scaleaspectfit and Autolayout Not Working Programmatically from Swift
iOS 8: Autorotation Is Not Working Without Storyboard
Replace C Style For-Loop in Swift 2.2.1
Backgroundtimeremaining Returns (35791394 Mins)
Fbsdk (New Facebook Sdk 4.0) Implementation Is Not Working for Login with Facebook
How to Catch Nsunknownkeyexception in Swift 2.2
How to Update a Swiftui View State from Outside (Uiviewcontroller for Example)
Create Alert Function in All View Controllers - Swift
Uitableviewcell Initwithstyle:Uitableviewcellstylesubtitle Is Not Working
Swift 3 Filter Array of Dictionaries by String Value of Key in Dictionary