Adding arguments to UIAlertAction - ios

I have 2 classes in separate files: lets call them NotificationManagement and NotificationReceiver
in my NotificationReceiver class i have the following code:
class NotificationReceiver: UIViewController{
//...
func showNotificationHandler(alert: UIAlertAction!) {
var storyboard : UIStoryboard = UIStoryboard(name: Constants.storyboardName, bundle: nil)
var vc : Article = storyboard.instantiateViewControllerWithIdentifier(Constants.articleVCTitle) as! Article
self.presentViewController(vc, animated: false, completion: nil)
}
func dismissNotificationHandler(alert: UIAlertAction!) {
Constants.articleAddress = ""
}
func showAlert(title:String, message:String) {
let alert = UIAlertController(title: title,
message: message, preferredStyle: .Alert)
let okAction = UIAlertAction(title: Messages.showMsg, style: .Default , handler: showNotificationHandler)
let dismissAction = UIAlertAction(title: Messages.discardMsg, style: .Cancel, handler: dismissNotificationHandler)
alert.addAction(dismissAction)
alert.addAction(okAction)
self.presentViewController(alert, animated: false, completion: nil)
}
//...
}
Now I want to put handling of this notification in NotificationManagement class instead the NotificationReceiver class. However if I do put it there i need something like that in the handler, to pass the information about current view controller:
func showNotificationHandler(alert: UIAlertAction!, currentViewController: UIViewController) {
var storyboard : UIStoryboard = UIStoryboard(name: Constants.storyboardName, bundle: nil)
var vc : Article = storyboard.instantiateViewControllerWithIdentifier(Constants.articleVCTitle) as! Article
currentViewController.presentViewController(vc, animated: false, completion: nil)
}
But then i cant compile and the errors are really misleading like the compiler cannot find style .Default (and its because i added arguments to the showNotificationHandler ). I would like to use the function in NotificationReceiver like this :
let notificationManagement = NotificationManagement()
notificationManagement.showAlert("title",message: "message")

Related

Swift: How do I add a name to the UITextView in a UIAlertController?

So I have a UITextView in a UIAlertController and later in the code I am writing the following:
for(var i: Int = 0; i < self.codesdemo.count; i++) {
if let code = self.textField.text {
if code == codesdemo[i] {
// This should present view controller if codes is real/worked
let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let viewController = storyboard.instantiateViewControllerWithIdentifier("Demo") as UIViewController
self.presentViewController(viewController, animated: true, completion: nil)
}
}
}
}))}
Basically saying that if someone writes [i] in the textView it goes to another viewcontroller.
Here is my full code that relates:
#IBAction func EnterCode(sender: AnyObject) {
let alert = UIAlertController(title: "Enter Code", message: "Enter a code to access your chatroom", preferredStyle: .Alert)
alert.addTextFieldWithConfigurationHandler { (textField:UITextField) -> Void in
textField.placeholder = "Enter Code"
}
alert.addAction(UIAlertAction(title: "Enter", style: .Default, handler: { (action:UIAlertAction) -> Void in
let textField = alert.textFields!.first!
alert.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
// Loops through the codes array
for(var i: Int = 0; i < self.codesdemo.count; i++) {
if let code = self.textField.text {
if code == codesdemo[i] {
// This should present view controller if codes is real/worked
let storyboard = UIStoryboard(name: "Main", bundle: NSBundle.mainBundle())
let viewController = storyboard.instantiateViewControllerWithIdentifier("Demo") as UIViewController
self.presentViewController(viewController, animated: true, completion: nil)
}
}
}
}))}
In this section: if let code = self.textField.text {
I get an error that says: Value type Homeviewcontroller (which is the viewcontroller)has no member of textField. I don't understand because I thought when I created the textField in the UIAlertController it is called textField I am wondering if there is something I need to do to rename it so I am able to fix this error. Can someone please help?
You are trying to present UIAlertController within action handler block.. that's reason your alertview will not appear in view:
I have edited some line of code of button action method ..here is code
#IBAction func EnterCode(sender: AnyObject) {
let alert = UIAlertController(title: "Enter Code", message: "Enter a code to access your chatroom", preferredStyle: .Alert)
alert.addTextFieldWithConfigurationHandler{ (textField:UITextField!) -> Void in
textField.placeholder = "Enter Code"
}
alert.addAction(UIAlertAction(title: "Enter", style: .Default, handler: { (action:UIAlertAction!) -> Void in
let textField: UITextField = alert.textFields!.first! as UITextField
alert.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: nil))
for(var i: Int = 0; i < self.codesdemo.count; i++) {
if let code: String = textField.text {
if code == codesdemo[i] {
// This should present view controller if codes is real/worked
//other code here
}
}
}
}))
self.presentViewController(alert, animated: true, completion: nil)
}

presentViewController() pops the view behind the last view

I'm trying to perform a transition to another UIViewController in another storyboard but the problem is that the view that I want to display pops behind the view where I'm from.
I know that because my app includes a Snapchat-like navigation between views, so I can drag the view to the left or the right and I can see the view behind.
Here is how I attempt to do that :
#IBAction func account(sender: UIButton) {
if self._isOnline {
self.pageController?.reverseViewControllerAnimated(true)
}
else {
let alertView = UIAlertController(title: "blablablabla", message: "blablablabla", preferredStyle: .Alert)
alertView.addAction(UIAlertAction(title: "No", style: .Cancel, handler: nil))
alertView.addAction(UIAlertAction(title: "Yes", style: .Default, handler: { (alertAction) -> Void in
let storyboard = UIStoryboard(name: "SignUpLogin", bundle: NSBundle.mainBundle())
let vc = storyboard.instantiateInitialViewController() as! UIViewController
self.presentViewController(vc, animated: false, completion: nil)
}))
presentViewController(alertView, animated: true, completion: nil)
}
}
With SignUpLogin that is the name of my second .storyboard file, here I'm in Heart.storyboard.
The action takes place in a UIAlertController, if the user press no, nothing append, if he press yes he's supposed to be redirected to the initial view of my SignUpLogin.storyboard file.
My problem come from the view at the bottom left corner. And if I use the code above in the view at the top right corner, that works ! Why ?
I have no idea of how I can do differently.
I've found the solution to my problem !
#IBAction func account(sender: UIButton) {
if self._isOnline {
self.pageController?.reverseViewControllerAnimated(true)
}
else {
let alertView = UIAlertController(title: Constants.LocalizedJoinOurBand, message: Constants.LocalizedNeedToCreatAnAccount, preferredStyle: .Alert)
alertView.addAction(UIAlertAction(title: Constants.LocalizedNo, style: .Cancel, handler: nil))
alertView.addAction(UIAlertAction(title: Constants.LocalizedYes, style: .Default, handler: { (alertAction) -> Void in
if let appDelegate = UIApplication.sharedApplication().delegate as? AppDelegate {
let storyboard = UIStoryboard(name: "SignUpLogin", bundle: NSBundle.mainBundle())
let vc = storyboard.instantiateInitialViewController() as! UIViewController
UIApplication.sharedApplication().keyWindow?.rootViewController = vc
}
}))
presentViewController(alertView, animated: true, completion: nil)
}
}
I don't know why in this case particularly but I have to directly set the rootViewController of my AppDelegate with this line :
UIApplication.sharedApplication().keyWindow?.rootViewController = vc

How to open another view controller when OK is pressed in alert.addAction in iOS 9

I want to display a viewcontroller called InViewController, when the "OK" from the add.alertAction is pressed.
if ((user) != nil) {
let alert = UIAlertController(title: "Success", message: "Logged In", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "OK", style: .Default) { _ in })
self.presentViewController(alert, animated: true){}
}
let alert = UIAlertController(title: "Success", message: "Logged In", preferredStyle: .Alert)
let action = UIAlertAction(title: "OK", style: .Default) { (action) -> Void in
let viewControllerYouWantToPresent = self.storyboard?.instantiateViewControllerWithIdentifier("SomeViewControllerIdentifier")
self.presentViewController(viewControllerYouWantToPresent!, animated: true, completion: nil)
}
alert.addAction(action)
self.presentViewController(alert, animated: true, completion: nil)
You can add a completionHandler to the UIAlertAction when you add it to do it what you want, like in the following way:
if ((user) != nil) {
let alert = UIAlertController(title: "Success", message: "Logged In", preferredStyle: .Alert)
let OKAction = UIAlertAction(title: "OK", style: .Default, handler: { _ -> Void in
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let nextViewController = storyBoard.instantiateViewControllerWithIdentifier("ViewControllerA") as! ViewControllerA
self.presentViewController(nextViewController, animated: true, completion: nil)
})
alert.addAction(OKAction)
self.presentViewController(alert, animated: true){}
}
To set the StoryboardID you can use Interface Builder in the Identity Inspector, see the following picture:
I put everything in the above code referencing ViewControllerA, you have to set the name of your UIViewController according what you want.
EDIT:
You are pointing to a UIView or some other object on the StoryBoard. Press the yellow indicator on top of the other objects which is your UIViewController, like in the following picture:
I hope this help you.
Here's how you can do that ,
I'm just updating the good work of Victor Sigler
you follow his answer with this little update ..
private func alertUser( alertTitle title: String, alertMessage message: String )
{
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let actionTaken = UIAlertAction(title: "Success", style: .default) { (hand) in
let storyBoard = UIStoryboard(name: "Main", bundle: nil)
let destinationVC = storyBoard.instantiateViewController(withIdentifier: "IntroPage") as? StarterViewController
self.present(destinationVC!, animated: true, completion: nil)
}
alert.addAction(actionTaken)
self.present(alert, animated: true) {}
}

Dismiss all UIAlertControllers currently presented

Is there a way to dismiss all UIAlertControllers that are currently presented?
This is specifically because from anywhere and any state of my app, I need to get to a certain ViewController when a push notification is pressed.
func dismissAnyAlertControllerIfPresent() {
guard let window :UIWindow = UIApplication.shared.keyWindow , var topVC = window.rootViewController?.presentedViewController else {return}
while topVC.presentedViewController != nil {
topVC = topVC.presentedViewController!
}
if topVC.isKind(of: UIAlertController.self) {
topVC.dismiss(animated: false, completion: nil)
}
}
This worked for me!
Edit: for iOS 13+
func dismissAnyAlertControllerIfPresent() {
guard let window = windows.first(where: { $0.isKeyWindow }),
var topVC = window.rootViewController?.presentedViewController else {return}
while topVC.presentedViewController != nil {
topVC = topVC.presentedViewController!
}
if topVC.isKind(of: UIAlertController.self) {
topVC.dismiss(animated: false, completion: nil)
}
}
You could subclass your UIAlertControllers, attach NSNotification observers to each which would trigger a method within the UIAlertController subclass to dismiss the alert controller, then post an NSNotification whenever you're ready to dismiss, ex:
class ViewController: UIViewController {
func presentAlert() {
// Create alert using AlertController subclass
let alert = AlertController(title: nil, message: "Message.", preferredStyle: UIAlertControllerStyle.Alert)
// Add observer to the alert
NSNotificationCenter.defaultCenter().addObserver(alert, selector: Selector("hideAlertController"), name: "DismissAllAlertsNotification", object: nil)
// Present the alert
self.presentViewController(alert, animated: true, completion:nil)
}
}
// AlertController subclass with method to dismiss alert controller
class AlertController: UIAlertController {
func hideAlertController() {
self.dismissViewControllerAnimated(true, completion: nil)
}
}
Then post the notification whenever you're ready to dismiss the alert (in this case, when the push notification is pressed):
NSNotificationCenter.defaultCenter().postNotificationName("DismissAllAlertsNotification", object: nil)
You can dismiss an UIAlertController that is currently being presented to the user this way:
self.dismissViewControllerAnimated(true, completion: nil)
I have written more generic code in swift 4,
This class shows alerts using utility class.
import UIKit
let APP_ORANGE_COLOR = UIColor(red: 1.000, green: 0.412, blue: 0.000, alpha: 1.00)
extension UIAlertController {
#objc func hideAlertController() {
self.dismiss(animated: false, completion: nil)
}
}
class AlertUtility: UIViewController {
static func showAlert(title: String!, message : String!, viewController: UIViewController) {
let alert = UIAlertController(title: title, message: message ,preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("ok", comment: "ok"), style: UIAlertActionStyle.cancel, handler: nil))
alert.view.tintColor = APP_ORANGE_COLOR
NotificationCenter.default.addObserver(alert, selector: #selector(alert.hideAlertController), name: DismissAllAlertsNotification, object: nil)
viewController.present(alert, animated: true, completion: nil)
}
static func showAlertAutoDismiss(title: String!, message : String!) -> Void {
//let appDelegate = UIApplication.shared.delegate as! AppDelegate
// the alert view
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let topWindow = UIWindow(frame: UIScreen.main.bounds)
topWindow.rootViewController = UIViewController()
topWindow.windowLevel = UIWindowLevelAlert + 0.8
topWindow.makeKeyAndVisible()
topWindow.rootViewController?.present(alert, animated: true, completion: {})
// change to desired number of seconds (in this case 5 seconds)
let when = DispatchTime.now() + 1
DispatchQueue.main.asyncAfter(deadline: when){
// your code with delay
alert.dismiss(animated: true, completion: nil)
topWindow.isHidden = true
}
}
static func showAlert(title: String!, message : String!) -> Void {
//let appDelegate = UIApplication.shared.delegate as! AppDelegate
// the alert view
let alert = UIAlertController(title: title, message: message, preferredStyle: .alert)
let topWindow = UIWindow(frame: UIScreen.main.bounds)
topWindow.rootViewController = UIViewController()
topWindow.windowLevel = UIWindowLevelAlert + 1
topWindow.makeKeyAndVisible()
topWindow.rootViewController?.present(alert, animated: true, completion: {})
alert.addAction(UIAlertAction(title: NSLocalizedString("ok", comment: "ok"), style: UIAlertActionStyle.cancel, handler: {(_ action: UIAlertAction) -> Void in
// continue your work
// important to hide the window after work completed.
// this also keeps a reference to the window until the action is invoked.
topWindow.isHidden = true
}))
NotificationCenter.default.addObserver(alert, selector: #selector(alert.hideAlertController), name: DismissAllAlertsNotification, object: nil)
alert.view.tintColor = APP_ORANGE_COLOR
}
static func showGenericErrorMessageAlert(viewController: UIViewController) {
let alert = UIAlertController(title: NSLocalizedString("error", comment: ""), message: NSLocalizedString("generic.error.message", comment: "") ,preferredStyle: UIAlertControllerStyle.alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("ok", comment: "ok"), style: UIAlertActionStyle.cancel, handler: nil))
alert.view.tintColor = APP_ORANGE_COLOR
viewController.present(alert, animated: true, completion: nil)
NotificationCenter.default.addObserver(alert, selector: #selector(alert.hideAlertController), name: DismissAllAlertsNotification, object: nil)
}
static func showComingSoonAlert(viewController: UIViewController) {
// the alert view
let alert = UIAlertController(title: "", message: NSLocalizedString("coming.soon", comment: ""), preferredStyle: .alert)
viewController.present(alert, animated: true, completion: {})
// change to desired number of seconds (in this case 5 seconds)
let when = DispatchTime.now() + 1
DispatchQueue.main.asyncAfter(deadline: when){
// your code with delay
alert.dismiss(animated: true, completion: nil)
}
NotificationCenter.default.addObserver(alert, selector: #selector(alert.hideAlertController), name: DismissAllAlertsNotification, object: nil)
}
// Show alert view with call back
static func showAlertWithCB(title: String, message: String, isConditional: Bool, viewController: UIViewController, completionBlock: #escaping (_: Bool) -> Void) {
let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.alert)
alert.view.tintColor = APP_ORANGE_COLOR
// Check whether it's conditional or not ('YES' 'NO, or just 'OK')
if isConditional
{
alert.addAction(UIAlertAction(title: NSLocalizedString("cancel", comment: ""), style: UIAlertActionStyle.cancel, handler: { (action: UIAlertAction) in
alert.dismiss(animated: true, completion: nil)
completionBlock(false)
}))
alert.addAction(UIAlertAction(title: NSLocalizedString("yes", comment: ""), style: UIAlertActionStyle.default, handler: { (action: UIAlertAction) in
alert.dismiss(animated: true, completion: nil)
completionBlock(true)
}))
}
else
{
alert.addAction(UIAlertAction(title: NSLocalizedString("ok", comment: "ok"), style: UIAlertActionStyle.default, handler: { (action: UIAlertAction) in
alert.dismiss(animated: true, completion: nil)
completionBlock(true)
}))
}
NotificationCenter.default.addObserver(alert, selector: #selector(alert.hideAlertController), name: DismissAllAlertsNotification, object: nil)
viewController.present(alert, animated: true, completion: nil)
}
static func showAlertWithTextField(viewController : UIViewController,completionBlock: #escaping (_: Bool, String) -> Void) {
//1. Create the alert controller.
let alert = UIAlertController(title: "Report Event?", message: "", preferredStyle: .alert)
alert.view.tintColor = APP_ORANGE_COLOR
//2. Add the text field. You can configure it however you need.
//AlertUtility.addte
alert.addTextField { (textField) in
let heightConstraint = NSLayoutConstraint(item: textField, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1, constant: 50)
textField.addConstraint(heightConstraint)
textField.placeholder = "Enter report reason here"
textField.tintColor = APP_ORANGE_COLOR
textField.autocapitalizationType = .sentences
}
// 3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: { [weak alert] (_) in
// Force unwrapping because we know it exists.
completionBlock(true,"")
//print("Text field: \(textField.text)")
}))
// 3. Grab the value from the text field, and print it when the user clicks OK.
alert.addAction(UIAlertAction(title: "Submit", style: .default, handler: { [weak alert] (_) in
let textField = alert?.textFields![0] // Force unwrapping because we know it exists.
completionBlock(true,(textField?.text)!)
//print("Text field: \(textField.text)")
}))
// 4. Present the alert.
viewController.present(alert, animated: true, completion: nil)
let textField = alert.textFields![0]
let v = UIView.init(frame: textField.frame)
textField.addSubview(v)
v.frame = textField.frame
v.bounds = textField.bounds
v.backgroundColor = APP_ORANGE_COLOR
v.superview?.bringSubview(toFront: v)
}
}
Use it in this way
//sample code - use in your view controller
AlertUtility.showAlertWithCB(title: NSLocalizedString("alert", comment: "") , message: (error)!, isConditional: false, viewController: self, completionBlock: { (yes) in
//Your actions on callback
self.popToPreviousController()
})
AlertUtility.showAlert(title: ALERT_TITLE, message: message, viewController: self)
Post notification when you want/need to auto dismiss alerts in app
let DismissAllAlertsNotification = Notification.Name("DismissAllAlertsNotification")
NotificationCenter.default.post(name: DismissAllAlertsNotification, object: nil)
They are modal: there will only be one of them at any time and it will have full focus.
It is your responsibility to create your alerts and it is the user that should be dismissing them. You need to make (or use) a custom view to display a stack of messages if you need further control.
I used the following extension to achieve this, I hope it may help you
First; you will have an extension for UIApplication to retrieve the RootViewController
extension UIApplication {
static func topViewControllerInNavigationStack(controller: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
if let navigationController = controller as? UINavigationController {
return topViewControllerInNavigationStack(controller: navigationController.visibleViewController)
}
if let tabController = controller as? UITabBarController {
if let selected = tabController.selectedViewController {
return topViewControllerInNavigationStack(controller: selected)
}
}
if let presented = controller?.presentedViewController {
return topViewControllerInNavigationStack(controller: presented)
}
return controller
}
}
Second; extension for UIAlertViewController
extension UIAlertController {
static func dismissPresentedAlertViewController() {
let viewController = UIApplication.topViewControllerInNavigationStack()
guard let isKindOf = viewController?.isKind(of:
UIAlertController.classForCoder()), isKindOf else {
return
}
viewController?.dismiss(animated: false, completion: nil)
}
}

Trying to segue to another view controller using an alert action, in Swift

In my code I have an action sheet that allows a user to either log-in or sign-up. When the user presses either one of these I want to define a handler that will segue them to the login/signup view controller. I'm very new to this so I'm not quite sure what I'm doing wrong but in my code I get an error that the types are not convertible. The code looks like this:
let actionSheet = UIAlertController(title: "Do you have an account?", message: "Please Log-In or Sign-Up", preferredStyle: .ActionSheet)
if let presentationController = actionSheet.popoverPresentationController {
presentationController.sourceView = sender as UIView
presentationController.sourceRect = sender.bounds
}
let dismissHandler = {
(action: UIAlertAction!) in
self.dismissViewControllerAnimated(true, completion: nil)
}
let signupHandler = ({
(ViewController: UIViewController!) in
let signupVC: nextViewController = segue.signupVC as nextViewController
})
let loginHandler = ({
(ViewController: UIViewController!) in
let loginVC: nextViewController = segue.loginVC as nextViewController
})
actionSheet.addAction(UIAlertAction(title: "Cancel", style: .Cancel, handler: dismissHandler))
actionSheet.addAction(UIAlertAction(title: "Log-In", style: .Default, handler: dismissHandler))
actionSheet.addAction(UIAlertAction(title: "Sign-Up", style: .Default, handler: signupHandler))
presentViewController(actionSheet, animated: true, completion: nil)
}
Any help would be greatly appreciated! Thanks in advance.
I dont know about segues but I normally just present them like this :
let loginVC = LoginViewController()
self.presentViewController(loginVC, animated: true, completion: nil)

Resources