I have a view controller but in the viewDidLoad() method I call another method named authenticateUserAndConfigureView() in which when the current user is nil it presents another view controller. However, it presents with it with a little delay - it firstly loads the main view controller and then the second one from the authenticateUserAndConfigureView() method.
Why is that?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
authenticateUserAndConfigureView()
setUpElements()
}
func setUpElements() {
// Style the elements
Utilities.styleFilledButton(signUpButton)
Utilities.styleHollowButton(loginButton)
}
func authenticateUserAndConfigureView() {
if Auth.auth().currentUser == nil {
print("No user signed in..")
} else {
print("User is already signed in.")
let navController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "HomeNVC")
navController.modalPresentationStyle = .fullScreen
self.present(navController, animated: true, completion: nil)
}
}
You can insert this line inside viewWillAppear
override func viewWillAppear(_ animated:Bool) {
super.viewWillAppear(animated)
authenticateUserAndConfigureView()
}
OR make this check before presenting the MainVC and according to it present the suitable vc
Related
I'm using NavigationController to operate the view.
If the value is exceeded on the first view and the value is not satisfied with the 'if' on the second view, I hope 'dismiss' will work.
I have made a similar simple example.
//First View
class ViewController: UIViewController {
#IBAction func goSecond(_ sender: Any) {
let Storyboard = UIStoryboard(name: "Main", bundle: nil)
let DvC = Storyboard.instantiateViewController(withIdentifier: "SecondViewController") as! SecondViewController
self.navigationController?.pushViewController(DvC, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
//Second View
class SecondViewController: UIViewController {
#IBAction func goThird(_ sender: Any) {
let Storyboard = UIStoryboard(name: "Main", bundle: nil)
let DvC = Storyboard.instantiateViewController(withIdentifier: "ThirdViewController") as! ThirdViewController
let num = 1
DvC.num = num
self.navigationController?.pushViewController(DvC, animated: true)
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
//Third View
class ThirdViewController: UIViewController {
var num = Int()
override func viewDidLoad() {
super.viewDidLoad()
print("num: ")
print(num)
if(num != 2) {
print("Success")
// dismiss(animated: true, completion: nil)
// navigationController?.dismiss(animated: true, completion: nil)
} else {
print("Failed")
}
}
}
The third view shows "Success", but the codes below it do not work.
dismiss(animated: true, completion: nil) // not work
navigationController?.dismiss(animated: true, completion: nil) // not work
Pressing the button on the first view moves to the second view, and pressing the button on the second view moves to the third view.
If the value passed when I go to the third view is not satisfied with 'if', I want to go back to the first view.
I want the second and third views to end, not just the screen shift.
Like the finish() of Android.
How can I exit the second and third views and return to the first view?
You are pushing the view controllers onto the stack. dismiss is for dismissing VCs presented modally.
What you want to do is pop the VC to go back one.
navigationController?.popViewController(animated: true)
or to go back to the root view.
navigationController?.popToRootViewController(animated: true)
My Scenario, In my project I am maintaining three ViewController (Main, VC1 and VC2). In main ViewController I am maintaining UIButton, This button click to VC1 presenting model view controller. Again, VC1 I am maintain UIButton with action click to present model to VC2. After VC2 presenting I need to dismiss VC1.
// presenting ViewController
var presentingViewController: UIViewController! = self.presentingViewController
self.dismissViewControllerAnimated(false) {
// go back to MainMenuView as the eyes of the user
presentingViewController.dismissViewControllerAnimated(false, completion: nil)
}
Try this in VC2's close button action
var vc = self.navigationController?.presentingViewController
while vc?.presentingViewController != nil {
vc = vc?.presentingViewController
}
vc?.dismiss(animated: true, completion: nil)
Hope this will work:
You need to have a UIViewController as a base, in this case MainViewController is the base ViewController. You need to use a protocol to call the navigation between Controllers.
you can do using protocol:-
In to your FirstViewController setting Protocol :
protocol FirstViewControllerProtocol {
func dismissViewController()
}
class FirstViewController: UIViewController {
var delegate:FirstViewControllerProtocol!
override func viewDidLoad() {
super.viewDidLoad()
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
#IBAction func goBack(sender: AnyObject) {
self.dismissViewControllerAnimated(true) {
self.delegate!.dismissViewController()
}
}
Now in your MainViewController
class MainViewController: UIViewController, FirstViewControllerProtocol {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
#IBAction func goToFirstViewController(sender: AnyObject) {
let viewController = self.storyboard?.instantiateViewControllerWithIdentifier(String(FirstViewController)) as! FirstViewController
viewController.delegate = self
self.presentViewController(viewController, animated: true, completion: nil)
}
//MARK: Protocol for dismiss
func dismissViewController() {
if let viewController = self.storyboard?.instantiateViewControllerWithIdentifier(String(SecondViewController)){
self.presentViewController(viewController, animated: true, completion: nil)
}
}
To solve the problem statement, what you can do is present VC2 using Main instead of VC1.
We can get the reference to Main in VC1 using
self.presentingViewController
When VC2 is presented, dismiss VC1 in the completionHandler of present(_:animated:completion:) method
class Main: UIViewController {
#IBAction func onTapButton(_ sender: UIButton) {
let vc1 = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "VC1")
self.present(vc1, animated: true, completion: nil)
}
}
class VC1: UIViewController {
#IBAction func onTapButton(_ sender: UIButton) {
let vc2 = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "VC2")
vc2.view.backgroundColor = .blue
self.dismiss(animated: false, completion: nil)
self.presentingViewController?.present(vc2, animated: true, completion: nil)
}
}
class VC2: UIViewController {
}
This approach is giving the expected output. Let me in case anything else is required.
You need to open vc2 from the mainVC - In order to do this you need a delegate method which will tell mainVC to close the current opened vc (i.e. vc1) and in the success block open vc2.
Code Snipet:-
dismiss(animated: false) {
//Open vc2
present(vc2)
}
In this case you need to call dismiss from the view controller over which your other view controllers are presented(Main in your case).
As you stated your situation in the question above Main presents VC1 and VC1 then presents VC2:
then calling Main.dismiss(animated: true, completion: nil) will dismiss VC1 and VC2 simultaneously.
If you don't have a reference to the root controller(Main), you could chain a couple of presentingViewController properties to access it; Something like this in the topmost controller(VC2):
presentingViewController?.presentingViewController?.dismiss(animated: true)
I hope this helps.
There is a present(_:animated:completion:) method which takes a completion. Inside that you can dismiss your VC1.
Your code will look something like this
#IBAction func ButtonTapped(_ sender: Any) {
present(VC2, animated: true) {
dismiss(animated: true, completion: nil)
}
}
I have two view controller
imag
1.first view controller is main and second is CustomAlertviw controller
main view controller is like above image, when I click continues am showing the customalertview controller, like image. when click the enter pin button I have to dismiss view contoller and show the view controller with uiview on main view controller but tried, it's showing the view controller, there one more custom view is not showing it crashing my app
main view code
#IBAction func backButtonClicked(_ sender: UIButton) {
let myAlert = UIStoryboard(name: "CustomAlertview", bundle: nil).instantiateViewController(withIdentifier: "CustomAlertViewController") as? CustomAlertViewController
myAlert?.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
myAlert?.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
self.present(myAlert!, animated: true, completion: nil)
}
Customalertview controller
#IBAction func enterPinButtonClick(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
let myAlert = UIStoryboard(name: "ScanAndPay", bundle: nil).instantiateViewController(withIdentifier: "ScanAndPayDetailsEntryViewController") as? ScanAndPayDetailsEntryViewController
myAlert?.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
myAlert?.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
self.present(myAlert!, animated: true, completion: nil)
myAlert.valuespass()
}
inside main view controller one function calling from the customalrerview
func valuespass()
{
DispatchQueue.main.async {
self.authType = 1
self.authStatus = false
print("this is calling")
self.pinStatusLabel.text = "Please enter a 4-digit Security PIN"
}
when I am calling this function from the custom alert view application is crashing and showing the hread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value this error. how to can show the all information after dismissing the custom view controller.
You are almost done. present ScanAndPay from FirstView instead of CustomAlertview.
I have done using Delegate as I think it will be fit in this scenario. Follow below steps -
Step 1:
In FirstViewController ,
Add - CustomAlertviewDelegate something like this -
class FirstViewController: UIViewController, CustomAlertviewDelegate {
Now replace your backButtonClicked method -
#IBAction func backButtonClicked(_ sender: UIButton) {
let myAlert = UIStoryboard(name: "CustomAlertview", bundle: nil).instantiateViewController(withIdentifier: "CustomAlertViewController") as? CustomAlertViewController
myAlert?.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
myAlert?.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
myAlert.delegate = self
self.present(myAlert!, animated: true, completion: nil)
}
Add a new Delegate method of CustomAlertviewDelegate -
func ScanAndPayView(){
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
let myAlert = UIStoryboard(name: "ScanAndPay", bundle: nil).instantiateViewController(withIdentifier: "ScanAndPayDetailsEntryViewController") as? ScanAndPayDetailsEntryViewController
myAlert?.modalPresentationStyle = UIModalPresentationStyle.overCurrentContext
myAlert?.modalTransitionStyle = UIModalTransitionStyle.crossDissolve
self.present(myAlert!, animated: true, completion: nil)
}
}
Step 2:
Now time for CustomAlertview ,
Add protocol for delegate top of the Class -
protocol CustomAlertviewDelegate: class {
func ScanAndPayView()
}
class CustomAlertview: UIViewController{
weak var delegate : CustomAlertviewDelegate!
...
override func viewDidLoad() { // Rest of your code
}
Now time to dismiss current view controller and notify FirstViewController for presenting ScanAndPay view Controller -
#IBAction func enterPinButtonClick(_ sender: Any) {
delegate.ScanAndPayView()
self.dismiss(animated: true, completion: nil)
}
Hope it will help you to achieve what you want.
As SplitViewController loads, I am showing a Login Screen. On successful login, I need to go back to parent view controller. Somehow dismissal is not working for me. Here is the code:
ParentViewController:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if !appDelegate.loggedIn {
self.performSegueWithIdentifier("loginScreen", sender: self)
}
}
override func viewDidLoad() {
super.viewDidLoad()
}
Child ViewController:
let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
appDelegate.loggedIn = true
self.dismissViewControllerAnimated(true, completion: nil)
The dismissal part never works. It just hangs on Login Screen.
Try one of the following:
1) remove self. keep only dismissViewControllerAnimated(true, completion: nil)
or remove self. and make it:
2) presentingViewController.dismissViewControllerAnimated(true, completion: nil)
or remove self. and try:
3) presentedViewController.dismissViewControllerAnimated(true, completion: nil)
Try this in your parent view controller:
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
if !appDelegate.loggedIn {
let loginVC: UIViewController = self.storyboard!.instantiateViewControllerWithIdentifier("LoginViewController") as UIViewController
loginVC = UIModalTransitionStyle.CoverVertical
self.parentViewController?.presentViewController(loginVC, animated: true, completion: nil)
}
}
You're instantiating the new view controller by its own name rather than by the segue name.
I have a view controller which is triggered from a UITabBarController (which is the root of my app) if a parse session doesn't exist.
override func viewDidAppear(animated: Bool) {
super.viewDidAppear(animated)
self.initialiseLogin()
}
func initialiseLogin()
{
if (PFUser.currentUser() == nil) {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc: UIViewController = storyboard.instantiateViewControllerWithIdentifier("LoginView") as! UIViewController
self.presentViewController(vc, animated: false, completion: nil)
}
}
Which works great. However the problem i'm having is how do i trigger this code when a logout is called from a child view controller in the tab bar controller
#IBAction func logoutAction(sender: AnyObject)
{
PFUser.logOut()
// ... what should i call here...
}
Protocols and delegates might be what you're looking for:
The Swift Programming Language - Protocols
Essentially, you can declare your UIViewControllers to conform to a protocol. Then set the delegates in your root view controller (or wherever you do your initialisation)
Then, you can do something like this:
#IBAction func logoutAction(sender: AnyObject)
{
PFUser.logOut()
delegate?.loggedOut()
}