I want to presentViewController when an alertController is presented.
I want such as if user presses the Ok button now i want to show the ViewController from AppDelegate on PushNotification.
I came to know on SO that UIAlertController is presented on different thread so want to present the ViewController after user presses Ok Button and moves on to main thread as below:
func presentRScreenFromRootViewController()
{
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let rViewController = storyboard.instantiateViewControllerWithIdentifier("rsh") as! R_SVC
dispatch_async(dispatch_get_main_queue(),{
self.window?.rootViewController?.presentViewController(rViewController, animated: true, completion: nil)
});
}
But I get warning as:
Attempt to present <BB.R_SVC: 0x15b983600> on
<SWRevealViewController: 0x15652df00> which is already presenting
<UIAlertController: 0x15b4f2dd0>
This is because the viewcontroller is presenting alertcontroller.Other times its working well..My rootViewController changes and moves to next screen..But when there is UIAlertController i get warning as attempt to present viewcontroller which is not in the view hierarchy
What am i doing wrong?
when creating UIAlertController, place you VCpresenting code in the an UIAlertAction like so
let alert = UIAlertController(title: "your title", message "move to next VC?", preferredStyle: UIAlertController: UIAlertControllerStyle.Alert)
let action: UIAlertAction = UIAlertAction(title: "yes move to next VC", style: UIAlertActionStyle.Default) {action -> Void in
let rViewController = storyboard.instantiateViewControllerWithIdentifier("rsh") as! R_SVC
self.presentViewController(rViewController, animated: true, completion: nil) })
alert.addAction(defaultAction)
self.presentViewController(alert, animated: true, completion: nil)
edit: Maybe try Dismiss all UIAlertControllers currently presented.
Related
I have issue with my app. Scenario is simple, after successfully account creation i wan't to dismiss current page or navigate to login page. My storyboard looks like this:
After successful account creation i having a popup with some info about it's ok, we send you verification email and after this popup i want to go to the page second from left - it's my main application page (now called "View Controller").
I tried dismiss window, but i have no effect there, it can only dismiss my popup window.
When i trying to redirect then i have issue with back button when is pressed,it lead to Sign Up page. There is some code:
// Create new user and send verification email
Auth.auth().createUser(withEmail: userEmail, password: userPassword) { user, error in if error == nil && user != nil {
self.sendVerificationMail();
self.displayAlertMessage(alertTitle: "Success", alertMessage: "Your account created successfully. We send you a verification email.");
// Redirect to View Controller
} else {
self.displayAlertMessage(alertTitle: "Unhandled error", alertMessage: "Undefined error #SignUpViewController_0002");
}
}
...
func displayAlertMessage(alertTitle: String, alertMessage:String, alertRedirection:String = ""){
let alert = UIAlertController(title: alertTitle, message: alertMessage, preferredStyle: UIAlertController.Style.alert);
let okAction = UIAlertAction(title:"Ok", style: UIAlertAction.Style.default, handler: nil);
alert.addAction(okAction);
self.present(alert, animated:true, completion:nil);
}
If i add this:
self.view.window!.rootViewController?.dismiss(animated: false, completion: nil)
After alert, it close only alert, before alert, it do nothing ( same as dismiss).
To dismiss and pop to main view you can use alert button action handler.
alert.addAction(UIAlertAction(title: "OK", style: UIAlertAction.Style.default, handler: { (action) in
self.dismiss(animated: true, completion: {
self.navigationController?.popToRootViewController(animated: true)
})
}))
Or you can use the navigation to specific view controller using below lines.
for viewController in self.navigationController!.viewControllers {
if viewController.isKind(of: <Your_Main_ViewController_Class_Name>.self) {
self.navigationController?.popToViewController(viewController, animated: true)
break
}
}
Your_Main_ViewController_Class_Name is the view controller that within your navigation controller stack to which you need to navigate. (ie) main view
To blindly navigate to main view once alert popup displayed, you can use completion handler while present the alert.
self.present(alert, animated: true, completion: {
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
self.navigationController?.popToRootViewController(animated: true)
}
})
well, you are using a navigation controller, for "present" a new view controller, you need to push it, for example.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewControllerWithIdentifier("IDOFYOURVIEW") as CLASS_NAME_OFYOUR_VIEWCONTROLLER
navigationController?.pushViewController(vc, animated: true)
with the last code you can "present" (push) a new view controller
Now, if you want to make a other action when your press backbutton, try with this lines
override func viewDidLoad {
super.viewDidLoad()
self.navigationItem.hidesBackButton = true
let newBackButton = UIBarButtonItem(title: "Back", style: UIBarButtonItemStyle.Bordered, target: self, action: "back:")
self.navigationItem.leftBarButtonItem = newBackButton
}
func back(sender: UIBarButtonItem) {
//in this part you can move to other view controller, examples
// Go back specific view in your navigation controller
for controller in self.navigationController!.viewControllers as Array {
if controller.isKind(of: NAMECLASS_OFYOUR_VIEWCONTROLLER.self) {
_ = self.navigationController!.popToViewController(controller, animated: true)
break
}
}
// Perform your custom actions
// ...
// Go back to the previous ViewController
self.navigationController?.popViewControllerAnimated(true)
}
Regards
It is my function I linked to button. It doesn't push to another ViewController. It should work in following way : User clicks button, button creates alert, alert stays in current ViewController or pushes to different existing ViewController. No idea why it is not working - alert shows and nothing happens. Identifier is set and correct.
let alert = UIAlertController(title: "Warning", message: "Aborting adding a routine scheme. Proceed?", preferredStyle: .alert)
alert.addAction(.init(title: "No", style: .cancel, handler: nil))
alert.addAction(.init(title: "Yes", style: .default, handler: { (action) in
alert.dismiss(animated: true, completion: nil)
// push to another VC
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "WorkoutViewController") as! WorkoutViewController
self.navigationController?.pushViewController(vc, animated: true)
}))
self.present(alert, animated: true, completion: nil)
Your current ViewController isn't embed in UINavigationController so this line does nothing
self.navigationController?.pushViewController(vc, animated: true)
... because navigationController is nil
If you want to just present ViewController use this
self.present(vc, animated: true, completion: nil)
I am trying to display an AlertController in Swift, but not from a UIViewController, but from a UIView that is called from its parent UIViewController. When I try to call the controller, I am getting the following error:
Warning: Attempt to present <UIAlertController: 0x7fa5544a3140> on
<UINavigationController: 0x7fa553830400> whose view is not in the window
hierarchy!
The code that I have which is trying to call the alertController is this:
let logInButton = TWTRLogInButton { (session, error) in
if let unwrappedSession = session {
let alert = UIAlertController(title: "Logged In",
message: "User \(unwrappedSession.userName) has logged in",
preferredStyle: UIAlertControllerStyle.Alert
)
alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
//self.presentViewController(alert, animated: true, completion: nil)
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentViewController(alert, animated: true, completion: nil)
} else {
NSLog("Login error: %#", error!.localizedDescription);
}
}
The commented line in the above block of code is what the original block of code came with, and the line below the comment is the code I tried to replace it with. Can anyone see what it is I'm doing wrong?
Is the root view controller already presenting a view controller? If so, you may need to use:
UIApplication.sharedApplication().keyWindow?.rootViewController?.presentedViewController?.presentViewController(alert, animated: true, completion: nil)
Having said that, it might be easier (and more consistent/appropriate) to use a delegate pattern and let the view tell whatever view controller is managing it to present the alert view controller.
In Swift 5
let window = UIApplication.shared.windows.filter {$0.isKeyWindow}.first
window?.rootViewController?.presentedViewController?.present(alert, animated: true, completion: nil)
for swift 5 :
UIApplication.shared.keyWindow?.rootViewController?.presentedViewController?.present(alertName, animated: true, completion: nil)
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
I have a view controller which is modally presented and when i run UIAlertController, keep getting a error message . how can i work around this.
the alert is trigged from a button which checks a text field is empty or not.
#IBAction func registerAction(sender: AnyObject) {
if(userEmail.isEmpty){
alertMessage("Fields Are Empty")
}
}
func alertMessage(userMessage:String){
var 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)
}
Error when i run the alert
Warning: Attempt to present <UIAlertController: 0x7f9bbb9060d0> on <AlertApp.CustomSignupVC: 0x7f9bb94accb0> which is already presenting <UIAlertController: 0x7f9bbb926660>
Try to add it in main operation queue.
dispatch_async(dispatch_get_main_queue()) {
self.presentViewController(myAlert, animated: true, completion: nil)
}
Check this relative question : Presenting a view controller modally from an action sheet's delegate in iOS8 - iOS10