Displaying an alert on a new View Controller - ios

I have a button that sends me on another View Controller. What I am trying is to display an alert on the next View Controller.

In the viewDidLoad() method of the new controller, create a new UIAlertController and display it like the following
let alertController = UIAlertController(title: "Default Style", message: "A standard alert.", preferredStyle: .Alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in
// ...
}
alertController.addAction(cancelAction)
let OKAction = UIAlertAction(title: "OK", style: .Default) { (action) in
// ...
}
alertController.addAction(OKAction)
self.presentViewController(alertController, animated: true) {
// ...
}
Note that this example was taken from the NSHipster website which offers nice articles about iOS. You can find the article about UIAlertController here. They also explain other stuff you can do with that class, like display an Action Sheet for example.

Swift 4
Create an extension of UIViewController with your function to display alert with required parameter arguments
extension UIViewController {
func displayalert(title:String, message:String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
alert.addAction((UIAlertAction(title: "OK", style: .default, handler: { (action) -> Void in
alert.dismiss(animated: true, completion: nil)
})))
self.present(alert, animated: true, completion: nil)
}
}
Now call this function from your view controller:
class TestViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
self.displayalert(title: <String>, message: <String>)
}
}

Related

UIAlertAction closure is not being called when presenting Controller is modal

I have a UIViewController which is embedeed in UINavigationController which is being presented modally over my application's keyWindow.rootViewController. When I present UIAlertController in any screen of the presented navigation controller, the alert controller is correctly displayed but the closures for any of the UIAlertAction are not being called after being pressed.
I am displaying the same alert controller with the same code in view controllers belonging to the main navigation controller of my app and the closures are called properly.
The code for presenting the alert is very simple, here's the snippet:
// Creating Alert
func createAlert() -> UIAlertController {
let actions: [UIAlertAction] = [
UIAlertAction(title: "Something", style: .default, handler: { _ in
self.setOriginalQueue(with: items, description: description, identifier: identifier)
self.setQueue()
}),
UIAlertAction(title: "Cancel", style: .cancel, handler: { _ in
normal()
})
]
let alert = UIAlertController(title: nil, message: message, preferredStyle: .actionSheet, actions: actions)
return alert
}
// In ViewController
DispatchQueue.main.async {
self.present(alert, animated: true, completion: nil)
}
So the question is, why are the closures not being called?
UIAlertController does not contain four types argument. See the document.
Once you fixed that, the rest will be automatically fixed like below.
For everyone's convenience I'll put the whole Modal view controller class source here.
class ModalViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
self.present(createAlert(), animated: true, completion: nil)
}
func createAlert() -> UIAlertController {
let actions: [UIAlertAction] = [
UIAlertAction(title: "Something", style: .default, handler: { _ in
print("Something")
}),
UIAlertAction(title: "Cancel", style: .cancel, handler: { _ in
print("Cancel")
})
]
let alert = UIAlertController(title: "Title", message: "Message", preferredStyle: .actionSheet)
for action in actions {
alert.addAction(action)
}
return alert
}
}
The line is wrong.
let alert = UIAlertController(title: nil, message: "message" , preferredStyle: .actionSheet, actions: actions)
You must be get error like that
Type of expression is ambiguous without more context
Change it like that:
return UIAlertController(title: YourTitle, message: YourMessage, preferredStyle: UIAlertController.Style.actionSheet)
So it can work.
Need to pass name of the method when you are presenting alert
self.present(createAlert(), animated: true, completion: nil)

UIAlertController is not working in model class

I want to show an alert. But I want to show it by creating a function in another class and call that function from a viewcontroller. But it does not work.
Here is code from my LoginViewController:
class LoginViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
LoginModel().show_alert()
}
}
Here is code from my LoginModel:
class LoginModel{
let controller = LoginViewController()
public func show_alert(){
let alert = UIAlertController(title: "Title", message: "Some Message",
preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler:
nil))
controller.present(alert, animated: true, completion: nil)
}
}
You need to pass the reference of UIViewController subclass to your LoginModel class, to present the UIAlertViewController on LoginViewController. You should call show alert once the LoginViewController view is appeared on the screen, move the call to ViewWillApear or viewDidApear method
final class LoginViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidApear(animated)
LoginModel().show_alert(on: self)
}
}
final class LoginModel {
public func show_alert(on vc: UIViewController) {
let alert = UIAlertController(title: "Title", message: "Some Message",
preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler:
nil))
vc.present(alert, animated: true, completion: nil)
}
}
ideally you should not create the UI related methods in model classes, they should be on on UIViewController/UIView classes or their extension methods. Model classes should not know anything about UI stuff. So you can easily create simple extension method on UIViewController and call the showAlert method from viewController.
extension UIViewController {
func showAlert(_ title: String = "Alert", message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler:
nil))
present(alert, animated: true, completion: nil)
}
}
you can call this method from UIViewController like
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
showAlert(message: "This is alert message")
}
Reminder: Your model shouldn't know about any UI related stuffs. Instead you should create an extension to UIViewController, or create free function
As a free function
func showAlertViewOnto(controller: UIViewController, detailInfo: (title: String?, message: String?), handler: ((UIAlertAction) -> Void)? = nil ) {
let alert = UIAlertController(title:detailInfo.title , message: detailInfo.message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler:
handler))
controller.present(alert, animated: true, completion: nil)
}
As an extension to your UIViewController
extension UIViewController {
func showAlertView(detailInfo: (title: String?, message: String?), handler: ((UIAlertAction) -> Void)? = nil ) {
let alert = UIAlertController(title:detailInfo.title , message: detailInfo.message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler:
handler))
self.present(alert, animated: true, completion: nil)
}
}
To Use it
showAlertViewOnto(controller: self, detailInfo: (title: "Hello ", message: "welcome to our service"), handler: { _ in
// here you can add code once ok is pressed
})
There is a logical error in your code. An instance of LoginViewController is already present (in the navigation stack or is the initial view controller) which appears on the screen.
You created a new instance of LoginViewController in your model class
let controller = LoginViewController()
which is not added to your navigation stack, so you don’t see it on the screen.
controller.present(alert, animated: true, completion: nil)
Presenting UIAlertController over the new instance will not show user an alert since the controller here itself is not present on the screen.
You will need to present UIAlertController from the instance visible on screen(the initial one). You could change the functionshow_alert to the following:
class LoginModel{
func showAlert(forController controller: UIViewController /*you could add title, message and other stuff here if needed.*/){
let alert = UIAlertController(title: "Title", message: "Some Message",
preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler:
nil))
controller.present(alert, animated: true, completion: nil)
}
And modify your call as follows:
LoginModel().showAlert(forController: self)

UIViewController and inheritance

I have multiple view controllers in my application. And in each of them I have to show alerts based on some conditions. Instead of adding alert controllers in each of them, I tried using inheritance as follows.
UIExtension.swift
class UIExtension: UIViewController {
func prepareAlert(title: String, message: String) -> UIAlertController {
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))
return alert
}
}
FirstViewController.swift
class FirstViewController: UIExtension {
//somewhere inside used the following
present(prepareAlert(title: "Error Validation", message: "invalid fields"), animated: true, completion: nil)
}
Similarly, used UIExtension in other viewcontrollers to show alerts. Is this way recommended?
For something like this, you are better off adding your prepareAlert method to a UIViewController extension. No subclassing required.
extension UIViewController {
func prepareAlert(title: String, message: String) -> UIAlertController {
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))
return alert
}
}
Then your view controller:
class FirstViewController: UIViewController {
//somewhere inside used the following
present(prepareAlert(title: "Error Validation", message: "invalid fields"), animated: true, completion: nil)
}
This allows you to use prepareAlert from any view controller include UITableViewController, UICollectionViewController, etc.
The approach is technically correct, although if you consider extending all UIViewController instances, regardless of any conditions, then it's more handy to extend it directly:
extension UIViewController {
func prepareAlert(title: String, message: String) -> UIAlertController {
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))
return alert
}
}
rmaddy was faster. But I decided not to delete the answer, but add another idea.
Another approach is to use protocol as a wrapper for certain functionality, and this is also widely used.
Say, you have a protocol, associated with some functionality, like generating alert, in this case:
protocol Alertable {} // or whatever else name
extension Alertable {
func prepareAlert(title: String, message: String) -> UIAlertController {
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))
return alert
}
}
Then, whenever you want certain UIViewController instance (or any other class, you get the idea) to be associated with this functionality, simply do:
class FirstViewController: UIViewController, Alertable {
// Now you can do the same:
present(prepareAlert(title: "Error Validation", message: "invalid fields"), animated: true, completion: nil)
}
To sum up, making up a protocol and extending it, and then associating certain classes with it - to expose that functionality - is a very handy and useful practice. In particular, this is a good way to encapsulate some functionality, for example, if you don't mean global/class-wide access to it.
Some extension method I am sharing with you that is used frequently in most application you can use it in any where of UIViewController class and enjoy :)
extension UIViewController {
let kAPPNAME = "Your App name"
func showOkAlert(_ msg: String) {
let alert = UIAlertController(title:
kAPPNAME, message: msg, preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
alert.addAction(okAction)
present(alert, animated: true, completion: nil)
}
func showOkAlertWithHandler(_ msg: String,handler: #escaping ()->Void){
let alert = UIAlertController(title: kAPPNAME, message: msg, preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default) { (type) -> Void in
handler()
}
alert.addAction(okAction)
present(alert, animated: true, completion: nil)
}
func showAlertWithActions(_ msg: String,titles:[String], handler:#escaping (_ clickedIndex: Int) -> Void) {
let alert = UIAlertController(title: kAPPNAME, message: msg, preferredStyle: .alert)
for title in titles {
let action = UIAlertAction(title: title, style: .default, handler: { (alertAction) in
//Call back fall when user clicked
let index = titles.index(of: alertAction.title!)
if index != nil {
handler(index!+1)
}
else {
handler(0)
}
})
alert.addAction(action)
}
present(alert, animated: true, completion: nil)
}
func showOkCancelAlertWithAction(_ msg: String, handler:#escaping (_ isOkAction: Bool) -> Void) {
let alert = UIAlertController(title: kAPPNAME, message: msg, preferredStyle: .alert)
let okAction = UIAlertAction(title: "OK", style: .default) { (action) -> Void in
return handler(true)
}
let cancelAction = UIAlertAction(title: "Cancel", style: .cancel) { (action) -> Void in
return handler(false)
}
alert.addAction(cancelAction)
alert.addAction(okAction)
present(alert, animated: true, completion: nil)
}
}
USES
class FirstViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//Only Info
self.showOkAlert("Hello")
//Info with Okay button
self.showOkAlertWithHandler("Hello Again") {
print("Tap to Okay")
}
//Show alert with Okay and cancel
self.showOkCancelAlertWithAction("Hello with Cancel") { (isOk) in
if isOk {
print("Okay")
}
else {
print("Cancel")
}
}
//Show alert with actions
self.showAlertWithActions("Hello with action", titles: ["Allow","Don't Allow", "Cancel"]) { (tapIndex) in
if tapIndex == 1 {
print("Allow")
}
}
}
}

How to create an alert in a subview class in Swift?

I have a view controller which contains a sub-view. And inside the sub-view class, I may need to pop out an alert when some condition is satisfied.
class GameViewController: UIViewController {
#IBOutlet var gameBoardUIView: GameBoardUIView
...
}
class GameBoardUIView: UIView {
...
func move() {
if !gameBoard.checkNextMoveExist() {
var alert = UIAlertController(title: "Game Over", message: nil, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Take Me Back", style: UIAlertActionStyle.Cancel, handler: {(action: UIAlertAction!) in
println("Taking user back to the game without restarting")
}))
alert.addAction(UIAlertAction(title: "New Game", style: UIAlertActionStyle.Destructive, handler: {(action: UIAlertAction!) in
println("Starting a new game")
self.restartGame()
}))
// This is where the question is
// self.presentViewController(alert, animated: true, completion: nil)
}
}
}
As you can see from the code, I cannot call presentViewController function to show the alert because my sub view is not a controller class. Should I somehow create a week reference to the parent controller inside the sub-view? What would be the best practice to implement such reference?
Swift 4
Just present the alert in UIApplication windows in root view controller:
let title = "Some title"
let message = "body message"
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let action = UIAlertAction(title: "Aceptar", style: .cancel, handler: nil)
alert.addAction(action)
UIApplication.shared.keyWindow?.rootViewController?.present(alert, animated: true, completion: nil)
there are couple of ways how you can catch a UIViewController in your UIView.
you can make any of your view controllers as a delegate to show an alert;
you can pass a view controller's reference to your view; and
in general you can always grab the rootViewController anywhere in your code.
you need to call the dismissViewControllerAnimated(_: completion:) on the same view controller when you'd like to dismiss your alert later.
thus, I'd do such a quick solution for your case:
func move() {
if !gameBoard.checkNextMoveExist() {
let rootViewController: UIViewController = UIApplication.sharedApplication().windows[0].rootViewController
var alert = UIAlertController(title: "Game Over", message: nil, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Take Me Back", style: UIAlertActionStyle.Cancel, handler: {(action: UIAlertAction!) in
rootViewController.dismissViewControllerAnimated(true, completion: nil)
println("Taking user back to the game without restarting")
}))
alert.addAction(UIAlertAction(title: "New Game", style: UIAlertActionStyle.Destructive, handler: {(action: UIAlertAction!) in
rootViewController.dismissViewControllerAnimated(true, completion: nil)
println("Starting a new game")
self.restartGame()
}))
rootViewController.presentViewController(alert, animated: true, completion: nil)
}
}

How would I create a UIAlertView in Swift?

I have been working to create a UIAlertView in Swift, but for some reason I can't get the statement right because I'm getting this error:
Could not find an overload for 'init' that accepts the supplied
arguments
Here is how I have it written:
let button2Alert: UIAlertView = UIAlertView(title: "Title", message: "message",
delegate: self, cancelButtonTitle: "OK", otherButtonTitles: nil)
Then to call it I'm using:
button2Alert.show()
As of right now it is crashing and I just can't seem to get the syntax right.
From the UIAlertView class:
// UIAlertView is deprecated. Use UIAlertController with a
preferredStyle of UIAlertControllerStyleAlert instead
On iOS 8, you can do this:
let alert = UIAlertController(title: "Alert", message: "Message", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "Click", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
Now UIAlertController is a single class for creating and interacting with what we knew as UIAlertViews and UIActionSheets on iOS 8.
Edit: To handle actions:
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: { action in
switch action.style{
case .Default:
print("default")
case .Cancel:
print("cancel")
case .Destructive:
print("destructive")
}
}}))
Edit for Swift 3:
let alert = UIAlertController(title: "Alert", message: "Message", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Click", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
Edit for Swift 4.x:
let alert = UIAlertController(title: "Alert", message: "Message", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { action in
switch action.style{
case .default:
print("default")
case .cancel:
print("cancel")
case .destructive:
print("destructive")
}
}))
self.present(alert, animated: true, completion: nil)
One Button
class ViewController: UIViewController {
#IBAction func showAlertButtonTapped(_ sender: UIButton) {
// create the alert
let alert = UIAlertController(title: "My Title", message: "This is my message.", preferredStyle: UIAlertController.Style.alert)
// add an action (button)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: nil))
// show the alert
self.present(alert, animated: true, completion: nil)
}
}
Two Buttons
class ViewController: UIViewController {
#IBAction func showAlertButtonTapped(_ sender: UIButton) {
// create the alert
let alert = UIAlertController(title: "UIAlertController", message: "Would you like to continue learning how to use iOS alerts?", preferredStyle: UIAlertController.Style.alert)
// add the actions (buttons)
alert.addAction(UIAlertAction(title: "Continue", style: UIAlertAction.Style.default, handler: nil))
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertAction.Style.cancel, handler: nil))
// show the alert
self.present(alert, animated: true, completion: nil)
}
}
Three Buttons
class ViewController: UIViewController {
#IBAction func showAlertButtonTapped(_ sender: UIButton) {
// create the alert
let alert = UIAlertController(title: "Notice", message: "Lauching this missile will destroy the entire universe. Is this what you intended to do?", preferredStyle: UIAlertController.Style.alert)
// add the actions (buttons)
alert.addAction(UIAlertAction(title: "Remind Me Tomorrow", style: UIAlertAction.Style.default, handler: nil))
alert.addAction(UIAlertAction(title: "Cancel", style: UIAlertAction.Style.cancel, handler: nil))
alert.addAction(UIAlertAction(title: "Launch the Missile", style: UIAlertAction.Style.destructive, handler: nil))
// show the alert
self.present(alert, animated: true, completion: nil)
}
}
Handling Button Taps
The handler was nil in the above examples. You can replace nil with a closure to do something when the user taps a button. For example:
alert.addAction(UIAlertAction(title: "Launch the Missile", style: UIAlertAction.Style.destructive, handler: { action in
// do something like...
self.launchMissile()
}))
Notes
Multiple buttons do not necessarily need to use different UIAlertAction.Style types. They could all be .default.
For more than three buttons consider using an Action Sheet. The setup is very similar. Here is an example.
You can create a UIAlert using the standard constructor, but the 'legacy' one seems to not work:
let alert = UIAlertView()
alert.title = "Alert"
alert.message = "Here's a message"
alert.addButtonWithTitle("Understood")
alert.show()
In Swift 4.2 and Xcode 10
Method 1 :
SIMPLE ALERT
let alert = UIAlertController(title: "Your title", message: "Your message", preferredStyle: .alert)
let ok = UIAlertAction(title: "OK", style: .default, handler: { action in
})
alert.addAction(ok)
let cancel = UIAlertAction(title: "Cancel", style: .default, handler: { action in
})
alert.addAction(cancel)
DispatchQueue.main.async(execute: {
self.present(alert, animated: true)
})
Method 2 :
ALERT WITH SHARED CLASS
If you want Shared class style(Write once use every where)
import UIKit
class SharedClass: NSObject {//This is shared class
static let sharedInstance = SharedClass()
//Show alert
func alert(view: UIViewController, title: String, message: String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let defaultAction = UIAlertAction(title: "OK", style: .default, handler: { action in
})
alert.addAction(defaultAction)
DispatchQueue.main.async(execute: {
view.present(alert, animated: true)
})
}
private override init() {
}
}
Now call alert like this in every ware
SharedClass.sharedInstance.alert(view: self, title: "Your title here", message: "Your message here")
Method 3 :
PRESENT ALERT TOP OF ALL WINDOWS
If you want to present alert on top of all views, use this code
func alertWindow(title: String, message: String) {
DispatchQueue.main.async(execute: {
let alertWindow = UIWindow(frame: UIScreen.main.bounds)
alertWindow.rootViewController = UIViewController()
alertWindow.windowLevel = UIWindowLevelAlert + 1
let alert2 = UIAlertController(title: title, message: message, preferredStyle: .alert)
let defaultAction2 = UIAlertAction(title: "OK", style: .default, handler: { action in
})
alert2.addAction(defaultAction2)
alertWindow.makeKeyAndVisible()
alertWindow.rootViewController?.present(alert2, animated: true, completion: nil)
})
}
Function calling
SharedClass.sharedInstance.alertWindow(title:"This your title", message:"This is your message")
Method 4 :
Alert with Extension
extension UIViewController {
func showAlert(withTitle title: String, withMessage message:String) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let ok = UIAlertAction(title: "OK", style: .default, handler: { action in
})
let cancel = UIAlertAction(title: "Cancel", style: .default, handler: { action in
})
alert.addAction(ok)
alert.addAction(cancel)
DispatchQueue.main.async(execute: {
self.present(alert, animated: true)
})
}
}
Now call like this
//Call showAlert function in your class
#IBAction func onClickAlert(_ sender: UIButton) {
showAlert(withTitle:"Your Title Here", withMessage: "YourCustomMessageHere")
}
Method 5 :
ALERT WITH TEXTFIELDS
If you want to add textfields to alert.
//Global variables
var name:String?
var login:String?
//Call this function like this: alertWithTF()
//Add textfields to alert
func alertWithTF() {
let alert = UIAlertController(title: "Login", message: "Enter username&password", preferredStyle: .alert)
// Login button
let loginAction = UIAlertAction(title: "Login", style: .default, handler: { (action) -> Void in
// Get TextFields text
let usernameTxt = alert.textFields![0]
let passwordTxt = alert.textFields![1]
//Asign textfileds text to our global varibles
self.name = usernameTxt.text
self.login = passwordTxt.text
print("USERNAME: \(self.name!)\nPASSWORD: \(self.login!)")
})
// Cancel button
let cancel = UIAlertAction(title: "Cancel", style: .destructive, handler: { (action) -> Void in })
//1 textField for username
alert.addTextField { (textField: UITextField) in
textField.placeholder = "Enter username"
//If required mention keyboard type, delegates, text sixe and font etc...
//EX:
textField.keyboardType = .default
}
//2nd textField for password
alert.addTextField { (textField: UITextField) in
textField.placeholder = "Enter password"
textField.isSecureTextEntry = true
}
// Add actions
alert.addAction(loginAction)
alert.addAction(cancel)
self.present(alert, animated: true, completion: nil)
}
Method 6:
Alert in SharedClass with Extension
//This is your shared class
import UIKit
class SharedClass: NSObject {
static let sharedInstance = SharedClass()
//Here write your code....
private override init() {
}
}
//Alert function in shared class
extension UIViewController {
func showAlert(title: String, msg: String) {
DispatchQueue.main.async {
let alert = UIAlertController(title: title, message: msg, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
}
Now call directly like this
self.showAlert(title: "Your title here...", msg: "Your message here...")
Method 7:
Alert with out shared class with Extension in separate class for alert.
Create one new Swift class, and import UIKit. Copy and paste below code.
//This is your Swift new class file
import UIKit
import Foundation
extension UIAlertController {
class func alert(title:String, msg:String, target: UIViewController) {
let alert = UIAlertController(title: title, message: msg, preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default) {
(result: UIAlertAction) -> Void in
})
target.present(alert, animated: true, completion: nil)
}
}
Now call alert function like this in all your classes (Single line).
UIAlertController.alert(title:"Title", msg:"Message", target: self)
How is it....
Click of View
#IBAction func testClick(sender: UIButton) {
var uiAlert = UIAlertController(title: "Title", message: "Message", preferredStyle: UIAlertControllerStyle.Alert)
self.presentViewController(uiAlert, animated: true, completion: nil)
uiAlert.addAction(UIAlertAction(title: "Ok", style: .Default, handler: { action in
println("Click of default button")
}))
uiAlert.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: { action in
println("Click of cancel button")
}))
}
Done with two buttons OK & Cancel
If you're targeting iOS 7 and 8, you need something like this to make sure you're using the right method for each version, because UIAlertView is deprecated in iOS 8, but UIAlertController is not available in iOS 7:
func alert(title: String, message: String) {
if let getModernAlert: AnyClass = NSClassFromString("UIAlertController") { // iOS 8
let myAlert: UIAlertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)
myAlert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
self.presentViewController(myAlert, animated: true, completion: nil)
} else { // iOS 7
let alert: UIAlertView = UIAlertView()
alert.delegate = self
alert.title = title
alert.message = message
alert.addButtonWithTitle("OK")
alert.show()
}
}
With the protocol extensions of Swift 2, you can make a protocol that provides a default implementation to your view controllers:
ShowsAlert.swift
import UIKit
protocol ShowsAlert {}
extension ShowsAlert where Self: UIViewController {
func showAlert(title: String = "Error", message: String) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .Alert)
alertController.addAction(UIAlertAction(title: "Ok", style: .Default, handler: nil))
presentViewController(alertController, animated: true, completion: nil)
}
}
ViewController.swift
class ViewController: UIViewController, ShowsAlert {
override func viewDidLoad() {
super.viewDidLoad()
showAlert(message: "Hey there, I am an error message!")
}
}
Show UIAlertView in swift language :-
Protocol UIAlertViewDelegate
let alert = UIAlertView(title: "alertView", message: "This is alertView", delegate:self, cancelButtonTitle:"Cancel", otherButtonTitles: "Done", "Delete")
alert.show()
Show UIAlertViewController in swift language :-
let alert = UIAlertController(title: "Error", message: "Enter data in Text fields", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
Simply do not provide otherButtonTitles in the constructor.
let alertView = UIAlertView(title: "Oops!", message: "Something
happened...", delegate: nil, cancelButtonTitle: "OK")
alertView.show()
But I do agree with Oscar, this class is deprecated in iOS 8, so there won't be no use of UIAlertView if you're doing an iOS 8 only app. Otherwise the code above will work.
For SWIFT4, I think, extending UIViewController and creating a reusable confirmation control is the most elegant way.
You can extend the UIViewController as below:
extension UIViewController {
func AskConfirmation (title:String, message:String, completion:#escaping (_ result:Bool) -> Void) {
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
self.present(alert, animated: true, completion: nil)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: { action in
completion(true)
}))
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { action in
completion(false)
}))
}
}
Then you can use it anytime:
AskConfirmation(title: "YOUR MESSAGE TITLE", message: "YOUR MESSAGE") { (result) in
if result { //User has clicked on Ok
} else { //User has clicked on Cancel
}
}
AlertView Swift 5 and above:-
let alert = UIAlertController(title: LocalizedStringConstant.alert, message: message, preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Retry", style: .cancel, handler: { (_) in
}))
self.present(alert, animated: true, completion: nil)
I found this one,
var alertView = UIAlertView();
alertView.addButtonWithTitle("Ok");
alertView.title = "title";
alertView.message = "message";
alertView.show();
not good though, but it works :)
Update:
but I have found on header file as:
extension UIAlertView {
convenience init(title: String, message: String, delegate: UIAlertViewDelegate?, cancelButtonTitle: String?, otherButtonTitles firstButtonTitle: String, _ moreButtonTitles: String...)
}
somebody may can explain this.
For iOS 13 Xcode 11+ Swift 5.X
UIAlertController can now provide Alerts as well as Action Sheets
Alerts
// First instantiate the UIAlertController
let alert = UIAlertController(title: "Title",
message: "Message ?",
preferredStyle: .alert)
// Add action buttons to it and attach handler functions if you want to
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
alert.addAction(UIAlertAction(title: "Just Do It!", style: .destructive, handler: nil))
alert.addAction(UIAlertAction(title: "Maybe", style: .default, handler: nil))
// Show the alert by presenting it
self.present(alert, animated: true)
Note that it's is a fundamental nature for all action buttons to dismiss the alert view when tapped. The style parameter is just for deciding the color of the text (and some default order in which the buttons should appear which ofc can be changed)
A sample handler function could be
func handler(_ action: UIAlertAction) {
if action.title == 'Title' {
// do stuff
}
}
As a side note, I would say instead of making 3 different handlers you can just make 1 and trace back to the element which provoked it in the manner shown above
We can also check alert.style but that again we can have multiple .default styled actions , I wouldn't recommend that
Action Sheets
The explanation is similar because the main difference here is that an alert interrupts the user whereas an action sheet slides from the bottom in an iPhone and appears as a popover in an iPad
The Purpose of action sheets is to guide the users in deciding his actions based on their current state. So you gotta treat action sheets like crossroads !. There is generally no message and the title is rendered as caption sized text
let action = UIAlertController(title: "What do you want to do with the message",
message: nil,
preferredStyle: .actionSheet)
action.addAction(UIAlertAction(title: "Cancel", style: .cancel))
for act in ["Save", "Post", "Discard"] {
action.addAction(UIAlertAction(title: act, style: .default, handler: nil))
}
self.present(action, animated: true)
The above code is going to work for an iPhone but will crash at runtime for an iPad because UIPopoverPresentationController is going to take charge of the alert and it won't be referencing anything at that time. So to avoid that you will have to provide the following chunk of code its mandatory
if let pop = action.popoverPresentationController {
let v = sender as! UIView
pop.sourceView = v
pop.sourceRect = v.bounds
}
Also in case of iPad tapping on anywhere outside the popover will dismiss it and the completion handler of .cancel action button will be called.
Hope that helps :) That being said, comment down below if you have any doubts
class Preview: UIViewController , UIAlertViewDelegate
{
#IBAction func MoreBtnClicked(sender: AnyObject)
{
var moreAlert=UIAlertView(title: "Photo", message: "", delegate: self, cancelButtonTitle: "No Thanks!", otherButtonTitles: "Save Image", "Email", "Facebook", "Whatsapp" )
moreAlert.show()
moreAlert.tag=111;
}
func alertView(alertView: UIAlertView, didDismissWithButtonIndex buttonIndex: Int)
{
if alertView.tag==111
{
if buttonIndex==0
{
println("No Thanks!")
}
else if buttonIndex==1
{
println("Save Image")
}
else if buttonIndex == 2
{
println("Email")
}
else if buttonIndex == 3
{
println("Facebook")
}
else if buttonIndex == 4
{
println("Whatsapp")
}
}
}
}
I have another trick. Suppose you have 5 classes where a logout alert to be applied. Try with swift class extension.
File- New- Swift class- Name it.
Add the following:
public extension UIViewController
{
func makeLogOutAlert()
{
var refreshAlert = UIAlertController(title: "Log Out", message: "Are You Sure to Log Out ? ", preferredStyle: UIAlertControllerStyle.Alert)
refreshAlert.addAction(UIAlertAction(title: "Confirm", style: .Default, handler: { (action: UIAlertAction!) in
self.navigationController?.popToRootViewControllerAnimated(true)
}))
refreshAlert.addAction(UIAlertAction(title: "Cancel", style: .Default, handler: { (action: UIAlertAction!) in
refreshAlert .dismissViewControllerAnimated(true, completion: nil)
}))
presentViewController(refreshAlert, animated: true, completion: nil)
}
}
Implement using : self.makeLogOutAlert(). Hope it helps.
I have made a singleton class to make this convenient to use from anywhere in your app: https://github.com/Swinny1989/Swift-Popups
You can then create a popup with multiple buttons like this:
Popups.SharedInstance.ShowAlert(self, title: "Title goes here", message: "Messages goes here", buttons: ["button one" , "button two"]) { (buttonPressed) -> Void in
if buttonPressed == "button one" {
//Code here
} else if buttonPressed == "button two" {
// Code here
}
}
or popups with a single button like this:
Popups.SharedInstance.ShowPopup("Title goes here", message: "Message goes here.")
Swift 3
The following is a simple example of how to create a simple alert with one button with Swift 3.
let alert = UIAlertController(title: "Title",
message: "Message",
preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default))
present(alert, animated: true)
In the above example the handle callback of the action has been omitted because the default behaviour of an alert view with one button is to disappear when the button is clicked.
Here is how to create another action, which could be added to the alert with "alert.addAction(action)". The different styles are .default, .destructive and .cancel.
let action = UIAlertAction(title: "Ok", style: .default) { action in
// Handle when button is clicked
}
I got the following UIAlertView initialization code to compile without errors (I thing the last, varyadic part is tricky perhaps). But I had to make sure the class of self (which I am passing as the delegate) was adopting the UIAlertViewDelegate protocol for the compile errors to go away:
let alertView = UIAlertView(
title: "My Title",
message: "My Message",
delegate: self,
cancelButtonTitle: "Cancel",
otherButtonTitles: "OK"
)
By the way, this is the error I was getting (as of Xcode 6.4):
Cannot find an initializer for type 'UIAlertView' that accepts an
argument list of type '(title: String, message: String, delegate:
MyViewController, cancelButtonTitle: String, otherButtonTitles:
String)'
As others mentioned, you should migrate to UIAlertController if you can target iOS 8.x+. To support iOS 7, use the code above (iOS 6 is not supported by Swift).
let alertController = UIAlertController(title: "Select Photo", message: "Select atleast one photo", preferredStyle: .alert)
let action1 = UIAlertAction(title: "From Photo", style: .default) { (action) in
print("Default is pressed.....")
}
let action2 = UIAlertAction(title: "Cancel", style: .cancel) { (action) in
print("Cancel is pressed......")
}
let action3 = UIAlertAction(title: "Click new", style: .default) { (action) in
print("Destructive is pressed....")
}
alertController.addAction(action1)
alertController.addAction(action2)
alertController.addAction(action3)
self.present(alertController, animated: true, completion: nil)
}
You can use this simple extension with n number of buttons and associated actions swift4 and above
extension UIViewController {
func popupAlert(title: String?, message: String?, actionTitles:[String?], actions:[((UIAlertAction) -> Void)?]) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
for (index, title) in actionTitles.enumerated() {
let action = UIAlertAction(title: title, style: .default, handler: actions[index])
alert.addAction(action)
}
self.present(alert, animated: true, completion: nil)
}
}
you can use it like ,
self.popupAlert(title: "Message", message: "your message", actionTitles: ["first","second","third"], actions:[
{action1 in
//action for first btn click
},
{action2 in
//action for second btn click
},
{action3 in
//action for third btn click
}, nil])
The reason it doesn't work because some value you passed to the function isn't correct. swift doesn't like Objective-C, you can put nil to arguments which are class type without any restriction(might be). Argument otherButtonTitles is defined as non-optional which its type do not have (?)at its end. so you must pass a concrete value to it.
#IBAction func Alert(sender: UIButton) {
var alertView:UIAlertView = UIAlertView()
alertView.title = "Alert!"
alertView.message = "Message"
alertView.delegate = self
alertView.addButtonWithTitle("OK")
alertView.show()
}
Try this
Use this code to display an alertview
let alertController = UIAlertController(title: "Hello Coders", message: "your alert message", preferredStyle: .Alert)
let defaultAction = UIAlertAction(title: "Close Alert", style: .Default, handler: nil)
alertController.addAction(defaultAction)
presentViewController(alertController, animated: true, completion: nil)
Reference: Swift Show Alert using UIAlertController
in xcode 9
let alert = UIAlertController(title: "Alert", message: "message", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated: true, completion: nil)
SWIFT 4 : Simply create a extension to UIViewController as follows:
extension UIViewController {
func showSuccessAlert(withTitle title: String, andMessage message:String) {
let alert = UIAlertController(title: title, message: message,
preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "OK".localized, style:
UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil)
}
}
Now in your ViewController, directly call above function as if they are provided by UIViewController.
yourViewController.showSuccessAlert(withTitle:
"YourTitle", andMessage: "YourCustomTitle")
Or just do this
let alert = UIAlertController(title: "Alert", message: "Saved Successfully", preferredStyle: UIAlertController.Style.alert)
alert.addAction(UIAlertAction(title: "Ok", style: UIAlertAction.Style.default, handler: nil))
self.present(alert, animated: true, completion: nil)
try This.
Put Bellow Code In Button.
let alert = UIAlertController(title: "Your_Title_Text", message: "Your_MSG", preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: "Your_Text", style: UIAlertActionStyle.default, handler: nil))
self.present(alert, animated:true, completion: nil)
Here is a funny example in Swift:
private func presentRandomJoke() {
if let randomJoke: String = jokesController.randomJoke() {
let alertController: UIAlertController = UIAlertController(title:nil, message:randomJoke, preferredStyle: UIAlertControllerStyle.Alert)
alertController.addAction(UIAlertAction(title:"Done", style:UIAlertActionStyle.Default, handler:nil))
presentViewController(alertController, animated:true, completion:nil)
}
}
Here is a pretty simple function of AlertView in Swift :
class func globalAlertYesNo(msg: String) {
let alertView = UNAlertView(title: "Title", message: msg)
alertView.messageAlignment = NSTextAlignment.Center
alertView.buttonAlignment = UNButtonAlignment.Horizontal
alertView.addButton("Yes", action: {
print("Yes action")
})
alertView.addButton("No", action: {
print("No action")
})
alertView.show()
}
You have to pass message as a String where you use this function.
The Old Way: UIAlertView
let alertView = UIAlertView(title: "Default Style", message: "A standard alert.", delegate: self, cancelButtonTitle: "Cancel", otherButtonTitles: "OK")
alertView.alertViewStyle = .Default
alertView.show()
// MARK: UIAlertViewDelegate
func alertView(alertView: UIAlertView, clickedButtonAtIndex buttonIndex: Int) {
switch buttonIndex {
// ...
}
}
The New Way: UIAlertController
let alertController = UIAlertController(title: "Default Style", message: "A standard alert.", preferredStyle: .Alert)
let cancelAction = UIAlertAction(title: "Cancel", style: .Cancel) { (action) in
// ...
}
alertController.addAction(cancelAction)
let OKAction = UIAlertAction(title: "OK", style: .Default) { (action) in
// ...
}
alertController.addAction(OKAction)
self.presentViewController(alertController, animated: true) {
// ...
}

Resources