I'm having a problem performing an UIAlertViewController in ViewController.
This is what I currently have
func displayLoginResult(viewModel: Login.PerformLogin.ViewModel) {
endLoader(loader: loaderLogin)
if let errorMessage = viewModel.displayedError {
print(errorMessage.message)
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)
}
else {
router.navigateToGroupsScene()
}
}
I've tried deleting DerivedData but nothing. I'm just considering the case that viewModel.displayedError is not nil (not the else case, just the if). I've seen if I comment this line:
self.presentViewController(alert, animated: true, completion: nil)
all works but obviously any Dialog is displayed which is not what I want. I'm a bit frustrades due to I've never had a problem like this and Xcode provides me not much information.
Exception on Xcode:
Threads details:
Any further information you need, just let me know and I will provide you!
Thank you so much.
Looks like you forgot to remove observer, add this code to your LoginViewController class:
override func viewDidDisappear(animated: Bool) {
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillShowNotification, object: nil)
NSNotificationCenter.defaultCenter().removeObserver(self, name: UIKeyboardWillHideNotification, object: nil)
}
Could you please try using below code:
func displayLoginResult(viewModel: Login.PerformLogin.ViewModel) {
endLoader(loader: loaderLogin)
if let errorMessage = viewModel.displayedError {
print(errorMessage.message)
let alert = UIAlertController(title: "Error", message: "Enter data in Text fields", preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.presentViewController(alert, animated: true, completion: nil)
})
}
else {
router.navigateToGroupsScene()
}
}
Related
I'm trying to limit the show of code so I just want to call function containing two strings to create a uialert faster with 1 line instead of 5/
The error I'm getting
Use of unresolved identifier 'present'
at the line
present(alert, animated: true, completion: nil)
// Controlling Alerts for Errors
func showAlert(titleString: String, messageString: String) {
// Alert to go to Settings
let alert = UIAlertController(title: titleString, message: messageString, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Dismiss", style: .default, handler: { _ in
alert.dismiss(animated: true, completion: nil)
}))
self.present(alert, animated: true, completion: nil)
}
In the comments, you explained that this is a stand-alone function. It should work if you make it an extension to UIViewController, for instance:
extension UIViewController {
public func showAlert(_ title:String, _ message:String) {
let alertVC = UIAlertController(
title: title,
message: message,
preferredStyle: .alert)
let okAction = UIAlertAction(
title: "OK",
style: .cancel,
handler: { action -> Void in
})
alertVC.addAction(okAction)
present(
alertVC,
animated: true,
completion: nil)
}
}
And to call it in a UIViewController:
showAlert(
"Could Not Send Email",
"Your device could not send e-mail. Please check e-mail configuration and try again."
)
What is the best way to display an alert in any view in my app when the connection is lost.
Currently using:
NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(AppDelegate.networkStatusChanged(_:)), name: ReachabilityStatusChangedNotification, object: nil)
Reach().monitorReachabilityChanges()
func networkStatusChanged(notification: NSNotification) {
if let info = notification.userInfo as? [String:String] {
let status = info["Status"]!
if !status.containsString("Online") {
}
}
}
UIAlertViews have been deprecated, use UIAlertController instead.
let alert = UIAlertController(title: "Error", message: "You you seem to have lost internet connectivity.", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "Dismiss", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
Hello I have a utility class in which I have declared AlertViewFunction like this
func displayAlertMessage(userMessage: String,//controller){
let myAlert = UIAlertController(title: "Alert", message: userMessage, preferredStyle: UIAlertControllerStyle.Alert);
let okAction = UIAlertAction(title: "Ok", style: UIAlertActionStyle.Default, handler: nil)
myAlert.addAction(okAction);
self.presentViewController(myAlert, animated: true, completion: nil)
}
The problem is I can't use self here
self.presentViewController(myAlert, animated: true, completion: nil)
I want to pass a controller to this function so I can use like this
controller.presentViewController(myAlert, animated: true, completion: nil)
How Can I pass a controller from any ViewController. Lets say If I am in LoginViewController
Utility().displayAlertMessage(Message.INTERNETISNOTCONNECTED,//controller)
Utility().displayAlertMessage(Message.INTERNETISNOTCONNECTED, controller: self)
and
func displayAlertMessage(userMessage: String, controller: UIViewController)
{
controller?.presentViewController(myAlert, animated: true, completion: nil)
}
pass in the view controller as an argument to the function.
func displayAlertMessage(controller: UIViewController, title: String, message: String?) {
let alert = UIAlertController(title: title, message: message, preferredStyle: .Alert)
let okAction = UIAlertAction(title: "Ok", style: .Default, handler: nil)
alert.addAction(okAction)
controller.presentViewController(alert, animated: false, completion: nil)
}
Alternatively you can even return the alert to the caller of the function for further customization by saying:
func displayAlertMessage(title: String, message: String?) -> UIAlertController {
let alert = UIAlertController(title: title, message: message, preferredStyle: .Alert)
let okAction = UIAlertAction(title: "Ok", style: .Default, handler: nil)
alert.addAction(okAction)
return alert
}
class controller: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
let alert = displayAlertMessage("title", message: nil)
presentViewController(alert, animated: true, completion: nil)
}
}
I have the following code:
/// Creates Alerts on screen for user.
func notifyUser(title: String, message: String) -> Void
{
let alert = UIAlertController(title: title,
message: message,
preferredStyle: UIAlertControllerStyle.Alert)
let cancelAction = UIAlertAction(title: "OK",
style: .Cancel, handler: nil)
alert.addAction(cancelAction)
UIApplication.sharedApplication().keyWindow?.rootViewController!.presentViewController(alert, animated: true,
completion: nil)
}
Which shows the following Alert:
I would prefer the Alert to appear for maybe 1-2 seconds and auto dismiss without having to click ok or dismiss. Is this possible?
Yes it's completely possible, I think the #Duncan C approach will work very well and it's self explanatory, so I going to explain you in code the #Duncan approach and another approach is using delays with the Grand Central Dispatch(GCD).
First Approach: Using the NSTimer class
// set the UIAlerController property
var alert: UIAlertController!
func notifyUser(title: String, message: String, timeToDissapear: Int) -> Void
{
alert = UIAlertController(title: title,
message: message,
preferredStyle: UIAlertControllerStyle.Alert)
let cancelAction = UIAlertAction(title: "OK",
style: .Cancel, handler: nil)
alert.addAction(cancelAction)
UIApplication.sharedApplication().keyWindow?.rootViewController!.presentViewController(alert, animated: true,
completion: nil)
// setting the NSTimer to close the alert after timeToDissapear seconds.
_ = NSTimer.scheduledTimerWithTimeInterval(Double(timeToDissapear), target: self, selector: Selector("dismissAlert"), userInfo: nil, repeats: false)
}
Second Approach: Using GCD
// set the UIAlerController property
var alert: UIAlertController!
func notifyUser(title: String, message: String, timeToDissapear: Int) -> Void
{
alert = UIAlertController(title: title,
message: message,
preferredStyle: UIAlertControllerStyle.Alert)
let cancelAction = UIAlertAction(title: "OK",
style: .Cancel, handler: nil)
alert.addAction(cancelAction)
UIApplication.sharedApplication().keyWindow?.rootViewController!.presentViewController(alert, animated: true,
completion: nil)
// Delay the dismissal by timeToDissapear seconds
let delay = Double(timeToDissapear) * Double(NSEC_PER_SEC)
let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(time, dispatch_get_main_queue()) { [weak self] in
self!.alert.dismissViewControllerAnimated(true, completion: nil)
}
}
And then you can call it in anywhere you want like in the following way :
self.notifyUser("Hello", message: "World", timeToDissapear: 3)
I hope this help you.
Here Is the code for Swift 4 Please Refer...Thank you
let alert = UIAlertController(title: "Success", message: "Record Updated Successfully", preferredStyle: UIAlertController.Style.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)
DispatchQueue.main.asyncAfter(deadline: .now() + 2) {
alert.dismiss(animated: true, completion: nil)
}
Sure. A UIAlertController is a special type of UIViewController. You're displaying it using presentViewController:animated:completion:. Just save a pointer to the UIAlertController into an instance variable, start a timer, and when the timer fires, call dismissViewControllerAnimated:completion:. You might want to get rid of the OK button action in that case, and if you leave the OK button you'll need to test and make sure your code works if you click OK before the timer fires.
Try this code:
var timer = NSTimer.scheduledTimerWithTimeInterval(5.0, target: self, selector: "dismissAlert", userInfo: nil, repeats: true)
func dismissAlert()
{
// Dismiss the alert from here
alert.dismissViewControllerAnimated(false, completion: nil)
}
I tried it and this worked fine. You can set the timer inside
scheduledTimerWithTimeInterval
where the current time is set to 5.0 seconds
func alert2 (_ dictKey: String){
if self.presentedViewController == nil {
let alertController = UIAlertController(title: nil, message: dictKey, preferredStyle: .alert )
alertController.addAction(UIAlertAction(title: "START AGAIN", style: UIAlertActionStyle.default, handler: {(action:UIAlertAction!) in self.returnToStart()}))
alertController.addAction(UIAlertAction(title: "REQUEST PIN", style: UIAlertActionStyle.default, handler:{(action:UIAlertAction!) in self.pinCreate()
self.dismiss(animated: false, completion: nil)//This dismisses the alert
}))
self.present(alertController, animated: true,completion: nil)
}
}
This proved to be a simple solution
func notifyUser(message: String) -> Void {
let alert = UIAlertController(title: "", message: message, preferredStyle: UIAlertController.Style.alert)
present(alert, animated: true, completion: nil)
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { [unowned self] in
self.dismiss(animated: true)
}
}
To use:
notifyUser(message: "Image Saved")
I have various controllers in my app that all require validation, and when validation fails, I want to display an alert with the errors. Is there some best practice/design pattern for doing this? I could simply create a static function in a Helper class like so:
static func displayAlert(message: String, buttonTitle: String, vc: UIViewController)
{
let alertController = UIAlertController(title: "", message: message, preferredStyle: .Alert)
let okAction = UIAlertAction(title: buttonTitle, style: .Default, handler: nil)
alertController.addAction(okAction)
vc.presentViewController(alertController, animated: true, completion: nil)
}
But then I need to pass the view controller..which seems like bad practice. I could shoot off a notification and observe it, but that seems like overkill. Am I overthinking this, or is there some more acceptable way to go about handling something like this?
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)
}
}
Swift 4
I wanted this same functionality for myself, so I made a full extension. To use it, create a new swift file in your project and name it whatever you'd like. Place the following code inside:
import UIKit
extension UIViewController {
func presentAlertWithTitle(title: String, message: String, options: String..., completion: #escaping (Int) -> Void) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
for (index, option) in options.enumerated() {
alertController.addAction(UIAlertAction.init(title: option, style: .default, handler: { (action) in
completion(index)
}))
}
self.present(alertController, animated: true, completion: nil)
}
}
To use it (which so many people don't actually show, which can lead to confusion for a newbie like myself):
presentAlertWithTitle(title: "Test", message: "A message", options: "1", "2") { (option) in
print("option: \(option)")
switch(option) {
case 0:
print("option one")
break
case 1:
print("option two")
default:
break
}
}
As original answer from itstrueimryan at https://stackoverflow.com/a/30714429/6822183
Update for Swift 3:
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)
}
}
I may have found a better answer to this problem, via an article by Krakendev: https://krakendev.io/blog/subclassing-can-suck-and-heres-why.
The idea is to use protocol-oriented programming to create a default implementation of an alert just for UIViewControllers:
protocol Alertable {
func issueAlert()
}
extension Alertable where Self: UIViewController {
func issueAlert() {
// alert code here
}
}
Now, just like that, every UIViewController that adheres to Alertable will have the issueAlert() method available to them without even having to define its own implementation.
And, of course, we can define parameters for the issueAlert function as well:
extension Alertable where Self: UIViewController {
func issueAlert(title: "Default Title", message: String = "Default Message") {
// alert code here
}
}
So our view controller can do either:
issueAlert()
or
issueAlert(title: "Error", message: "Something went wrong")
Two advantages to this approach that I can think of are that you know if a view controller has access to this method just by looking at the Alertable protocol in the class definition, and individual view controllers can override this method if they want to provide custom functionality. Of course, now you can also specify the Alertable contract as a method parameter.
Answer from Sigex is completely fine, except the int indices passing to trace the button clicks might not make sense because, caller needed to keep track with int value. In that case passing string arguments and comparing them in switch case in completion block makes more sense to me. I would rather use like,
import UIKit
extension UIViewController {
func presentAlertWithTitle(title: String, message: String, options: String..., completion: #escaping (String) -> Void) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
for (index, option) in options.enumerated() {
alertController.addAction(UIAlertAction.init(title: option, style: .default, handler: { (action) in
completion(options[index])
}))
}
self.present(alertController, animated: true, completion: nil)
}
}
And test with,
class TestViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
presentAlertWithTitle(title: "Test", message: "A sample message", options: "start", "stop", "cancel") { (option) in
print("option: \(option)")
switch(option) {
case "start":
print("start button pressed")
break
case "stop":
print("stop button pressed")
break
case "cancel":
print("cancel button pressed")
break
default:
break
}
}
}
}
Why not create a Utility function that returns the AlertView to the ViewController?
self.presentViewController(Utilities.createAlertController("errorMessage"), animated: true, completion: nil);
Updated for swift 3:
if you want to show the alert message to user used below simple lines of code;
// function defination:
func showMessageToUser(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.present(alert, animated: true, completion: nil)
}
//function call :
self.showMessageToUser(title: "Alert", msg: "your message to user")
// Enjoy coding..!
I used Sigex's extension in my code, however I have added a check, if options were used or not.
If no options are given in the call, then the Alert only shows "OK" and completes with returning option 0.
extension UIViewController {
func presentAlertWithTitle(title: String, message: String, options: String..., completion: #escaping (Int) -> Void) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
if options.count == 0 {
let OKAction = UIAlertAction(title: "OK", style: .default, handler: { (action) in
completion(0)
})
alertController.addAction(OKAction)
} else {
for (index, option) in options.enumerated() {
alertController.addAction(UIAlertAction.init(title: option, style: .default, handler: { (action) in
completion(index)
}))
}
}
self.present(alertController, animated: true, completion: nil)
}
}
Just omit the part , options: "1","2" then default alert is shown.
I love Sigex's extension, but I spiced it up a bit to add style on button depending on the title
func presentAlertWithOptions(title: String, message: String, options: String..., completion: #escaping (Int) -> Void) {
let alertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
if options.count == 0 { //if there is no options, show a basic alert
let OKAction = UIAlertAction(title: "OK", style: .default, handler: { (action) in
completion(0)
})
alertController.addAction(OKAction)
} else { //alert with options
for (index, option) in options.enumerated() {
var alertStyle = UIAlertAction.Style.default
switch option { //check if we should style the buttons
case "Cancel": //cancel style
alertStyle = .cancel
case "Logout", "Discard Changes", "Discard", "Delete", "Remove": //destructive style
alertStyle = .destructive
default: break //keep as default
}
alertController.addAction(UIAlertAction(title: option, style: alertStyle, handler: { (action) in
completion(index)
}))
}
}
self.present(alertController, animated: true, completion: nil)
}
Swift 4.1
let alert = UIAlertController(title: "Atenção",message: "Mensagem Aqui",preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "Ok", style: .default, handler: nil))
self.present(alert, animated: true)