In my app where I use Parse.com framework, afer any operation for example sign up I would like to go to another sotyboard for example login, so I do this code:
user.signUpInBackgroundWithBlock({ (succeeded: Bool, error: NSError?) -> Void in
if error != nil{
// alert Error
} else {
let action = UIAlertController(title: "Congratulattion!", message: "Now yu can start chatting", preferredStyle: .Alert)
let ok = UIAlertAction(title: "OK", style: .Default, handler: { (alert) -> Void in
let mainVC = self.storyboard?.instantiateViewControllerWithIdentifier("login") as! LogInViewController
self.presentViewController(mainVC, animated: true, completion: nil)
})
action.addAction(ok)
self.presentViewController(action, animated: true, completion: nil)
}
afert this segue my NavgationBar disappears. My Application looks like that:
What Do I need to do, my Navbar doesn't disappear?
Picture with error which I see after segue from Sign Up App Chat to Welcome in Chat App using self.performSegueWithIdentifier("signup", sender: self)
I don't think you want to use the code self.storyboard?.instantiateViewControllerWithIdentifier("login") as! LogInViewController. It looks like you are going from your signup controller to the login controller in your code, so you might want to add a segue connecting those 2 in your storyboard, and if you make it a segue of type 'show', then the navigation bar will stay intact. Then you can call performSegue on this segue.
Related
I have a storyboard controlled app. On the register page, I want to send the user to the home page when pressing the register button. So i dragged a segue from the button to the home page. But then I cannot check conditions before the segue is performed. But if i create a segue and perform it programmatically, the home page comes over the register page, allowing the user to swipe back. Can someone tell me how to check conditions before that segue is performed, or not allow the user to go back to the register page if doing it programmatically. This is my storyboard. Main.storyboard
Xcode 12.0 Swift 5.0
First of all you need to connect "Register" button to an IBAction in your code;
In the IBAction you can call function:
func present(_ viewControllerToPresent: UIViewController, animated flag: Bool, completion: (() -> Void)? = nil).
If in condition everything is succesfull you call this function otherwise return with error.
Example of sign out button:
private func showLoginViewController() {
// Creates the view controller with the specified identifier
let vc = storyboard?.instantiateViewController(withIdentifier: "loginForm") as! LoginViewController
let navigationVC = UINavigationController(rootViewController: vc)
navigationVC.modalPresentationStyle = .fullScreen
present(navigationVC, animated: true, completion: nil)
}
// Tap on button
#IBAction func signOutUserButton(_: UIButton) {
let alertController = UIAlertController(title: nil, message: "Are you sure you want to sign out?", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Sign Out", style: .destructive, handler: { _ in
// Condition where I check possibility to sign out
self.signOut()
}))
alertController.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
present(alertController, animated: true)
}
private func signOut() {
let firebaseAuth = Auth.auth()
do {
try firebaseAuth.signOut()
// If everything is okay then perform segue
showLoginViewController()
} catch let signOutError as NSError {
// Otherwise show error
print("Error signing out: %#", signOutError)
}
}
Reconnect the segue from the controller to the destination.
Connect the button to an IBAction.
In the IBAction check conditions and call performSegue(withIdentifier:sender:) on success.
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
I am trying to write a login process for my app. I have embedded a navigation controller to HomeViewController and set it as the initial ViewController. How can I fix it such that when a user enters the wrong credentials the HomeViewController will not be shown at all?
This is what it is doing:
Correct credentials entered
Display LoginViewController -> User inputs credentials -> Display HomeViewController
Wrong credentials entered
Display LoginViewController -> User inputs credentials -> Display HomeViewController -> Display LoginViewController
Code for LoginViewController (look at the last block of code)
func handlingAuthentication(notification: NSNotification) {
let dict = notification.object as! NSDictionary
if dict["error"]! as! Bool == true {
let errorMessage = dict["message"] as! String
//initialize Alert Controller
let alertController = UIAlertController(title: "Authentication error", message: errorMessage, preferredStyle: .Alert)
//Initialize Actions
let okAction = UIAlertAction(title: "Ok", style: .Default){
(action) -> Void in
self.dismissViewControllerAnimated(true, completion: nil)
}
//Add Actions
alertController.addAction(okAction)
//Present Alert Controller
self.presentViewController(alertController, animated: true, completion: nil)
}
else
{
NSUserDefaults.standardUserDefaults().setBool(true, forKey: "isUserLoggedIn")
NSUserDefaults.standardUserDefaults().synchronize()
self.dismissViewControllerAnimated(true, completion:nil)
}
}
Code for HomeViewController
override func viewDidAppear(animated: Bool) {
let isUserLoggedIn = NSUserDefaults.standardUserDefaults().boolForKey("isUserLoggedIn")
if(!isUserLoggedIn){
self.performSegueWithIdentifier("toLoginVC", sender: self)
}
}
UPDATE
I've tried placing the code block in ViewDidLoad but I am still getting the same issue (in fact now I'm stuck on the homePage)
override func viewDidLoad() {
super.viewDidLoad()
let isUserLoggedIn = NSUserDefaults.standardUserDefaults().boolForKey("isUserLoggedIn")
if(!isUserLoggedIn){
self.performSegueWithIdentifier("toLoginVC", sender: self)
}
usernameLabel.text = Data.sharedInstance.userName
getTaskDetails()
displayTask.dataSource = self
}
If the main view controlled decides and displays the login you will inevitable see it on screen because it's already in the process of displaying - so it shouldn't do it. You should have some other controller, perhaps a splash view controller, which decides to show either the login or the main view.
In your login view controller the alert OK button calls dismiss, this is the reason the login controller disappears and re-appears again (after showing the main controller for a short time).
I am having a NavigationController. In the ThirdViewController I am performing some task and on failure, I show Alert messages using UIAlertController.
Sometimes, when I start the task and come back to SecondViewController, I get the error message displayed on SecondViewController and on clicking OK, everything gets black below Navigation bar. I am left with only Navigation bar and if I go back again to FirstViewController, it also has the same black view except Navigation bar.
Presenting Alert of the ViewController which is not in the window hierarchy creates the issue. I do not want the Alert to be presented if I am not on the screen.
It is easily reproducible if I go back swiping the ViewController slowly.
What is the best way to handle it?
Sharing my code,
Button action in ThirdViewController
func buttonTapped() {
APIManager.sharedManager.getDetails(completion: { (details ,error) -> Void in
guard error == nil else {
Alert.errorMsg(error!.localizedDescription, viewController: self, goBack: false)
return
}
print(details)
}
}
class Alert: NSObject {
/* Error message */
class func errorMsg(message: String, viewController: UIViewController?, goBack: Bool = false) {
let alertView = UIAlertController(title: "Error", message: message, preferredStyle: .Alert)
let action = UIAlertAction(title: "OK", style: UIAlertActionStyle.Default) { (alert: UIAlertAction) -> Void in
if goBack == true && viewController != nil {
viewController!.navigationController?.popToRootViewControllerAnimated(true)
}
}
alertView.addAction(action)
let controller = viewController ?? UIApplication.sharedApplication().keyWindow?.rootViewController
controller!.presentViewController(alertView, animated: true, completion: nil)
}
}
I created a CustomViewController and added a property 'isUnloading'. In viewWillDisappear, I set isUnloading = true. I check the property before presenting the Alert.
Since you did not share any code we don't know exactly what happens there. But if you do not want to show the alert if the view controller is not in the window hierarchy you could check if viewController.view.window is set before showing the alert view and show it only if it is set.
you can do something like,
class AlertHelper {
func showAlert(fromController controller: UIViewController) {
var alert = UIAlertController(title: "abc", message: "def", preferredStyle: .Alert)
controller.presentViewController(alert, animated: true, completion: nil)
}
}
called alert as,
var alert = AlertHelper()
alert.showAlert(fromController: self)
refer this link for more detail.
Hope this will help :)
Thank you for reading this. I would like to have a functions Swift file where I put all of the functions for my project into, that the other Swift files could call. I am trying to create an alert function in the functions file that, when I pass in a specific string, it shows a specific alert. It was working when it was in the main file, but when I moved it to the functions file, presentViewController is giving me an error, saying "Use of unresolved identifier 'presentViewController'." Please help! Here is my code:
in the functions file:
import Foundation
import UIKit
/**********************************************
Variables
***********************************************/
var canTapButton: Bool = false
var tappedAmount = 0
/**********************************************
Functions
***********************************************/
//the alert to ask the user to assess their speed
func showAlert(alert: String) -> Void
{
if(alert == "pleaseAssessAlert")
{
let pleaseAssessAlert = UIAlertController(title: "Welcome!", message: "If this is your firs time, I encourage you to use the Speed Assessment Tool (located in the menu) to figure which of you fingers is fastest!", preferredStyle: .Alert)
//ok button
let okButtonOnAlertAction = UIAlertAction(title: "Done", style: .Default)
{ (action) -> Void in
//what happens when "ok" is pressed
}
pleaseAssessAlert.addAction(okButtonOnAlertAction)
presentViewController(pleaseAssessAlert, animated: true, completion: nil)
}
else
{
println("Error calling the alert function.")
}
}
Thanks!
The presentViewController is the instance method of UIViewController class. So you can't access it on your function file like this.
You should change the function like:
func showAlert(alert : String, viewController : UIViewController) -> Void
{
if(alert == "pleaseAssessAlert")
{
let pleaseAssessAlert = UIAlertController(title: "Welcome!", message: "If this is your firs time, I encourage you to use the Speed Assessment Tool (located in the menu) to figure which of you fingers is fastest!", preferredStyle: .Alert)
//ok button
let okButtonOnAlertAction = UIAlertAction(title: "Done", style: .Default)
{ (action) -> Void in
//what happens when "ok" is pressed
}
pleaseAssessAlert.addAction(okButtonOnAlertAction)
viewController.presentViewController(pleaseAssessAlert, animated: true, completion: nil)
}
else
{
println("Error calling the alert function.")
}
}
Here, you are passing a UIViewController instance to this function and calling the presentViewController of that View Controller class.
In Swift 3:
The method presentViewController is replaced by present.
You can use it like the old one:
self.present(viewControllerToPresent, animated: true, completion: nil)
First, you need to check your NavigationController is appropriate or not?
If Yes, then Here is code for present and dismiss presentviewcontroller
For presenting PresentViewController :
let next = self.storyboard?.instantiateViewControllerWithIdentifier("Your view controller identifier") as! Yourviewcontroller
self.presentViewController(next, animated: true, completion: nil)
Dismiss Presentviewcontroller
self.dismissViewControllerAnimated(true, completion: nil)
I would say go with MidHun MP method above but, if you are looking for another way to do this without bringing in the UIViewController then:
func showAlert(alert : String) {
var window: UIWindow?
if(alert == "pleaseAssessAlert")
{
let pleaseAssessAlert = UIAlertController(title: "Welcome!", message: "If this is your firs time, I encourage you to use the Speed Assessment Tool (located in the menu) to figure which of you fingers is fastest!", preferredStyle: .Alert)
//ok button
let okButtonOnAlertAction = UIAlertAction(title: "Done", style: .Default)
{ (action) -> Void in
//what happens when "ok" is pressed
}
pleaseAssessAlert.addAction(okButtonOnAlertAction)
self.window?.rootViewController?.presentViewController(pleaseAssessAlert, animated: true, completion: nil)
}
else
{
println("Error calling the alert function.")
}
}
Presenting & navigation view controller has a problem with layoutsubviews function while using self.view or viewcontroller.view, so one must avoid those function.
Check:
func layoutsubviews not allows to provide the viewcontroller.view to work on it