viewController is presented before the segue has been passed - ios

I have a set of buttons and I want to send their title to the next page using segue . Here is what I have done :
// in my first page i have :
#IBAction func btn_language_action(_ sender: UIButton) {
let chosen_language = sender.currentTitle!
print(chosen_language)
let game_level = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "game_level") as! game_level_viewController
self.present(game_level, animated: false, completion: nil)
performSegue(withIdentifier: "GL", sender: chosen_language)
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let game_level_viewController = segue.destination as! game_level_viewController
game_level_viewController.language = sender as? String
}
and in the second view I have :
#IBOutlet weak var lang: UILabel!
var language : String?
override func viewDidLoad() {
super.viewDidLoad()
setUI()
}
func setUI (){
lang.text = language
print(language )
}
I can pass the information successfully however , however the view has already been loaded before I receive what was sent . Any idea how can I fix this ?
In the console I have :
language ==> nil
language ==> Optional("Persian")

the problem is due to this line
self.present(game_level, animated: false, completion: nil)
why you are presenting this controller even if you have given segue to the controller
Remove this two lines and all will work good
let game_level = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "game_level") as! game_level_viewController
self.present(game_level, animated: false, completion: nil)

You have written two lines which both are used for transition between view controllers, So when you use segue don't present viewcontroller simultaneously.
Problem in your code is in this line, try to remove below code.
self.present(game_level, animated: false, completion: nil)

Related

Can I use dismiss for screen movement using NavigationController?

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)

Xcode: How to know the viewController that has presented the current view?

I have two viewControllers "FirstViewController"&"SecondViewControler" that contain a button that presents a new viewController called "BibliothequesViewController" when a button is clicked:
#IBAction func onLibrariesButtonClicked(_ sender: Any) {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc: BibliothequesViewController = storyboard.instantiateViewController(withIdentifier: "BibliothequesViewController") as! BibliothequesViewController
self.present(vc, animated: true, completion: nil)
}
For the time being, the BibliothequesViewController contains a button that's redirects to the FirstViewController with a Segue:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
print("SegWay being performed")
// Every segway has a beginning point and ending point
// We're trying to access the ending point
// as type FullScreenMovieController
// Then we're setting the chosenMovie variable of FullScreenMovieController to 1
let vc = segue.destination as! FirstViewController
vc.receivedSelectedLibraryFromBibliothequesList = self.selectedLibrary
print("vc.receivedSelectedLibraryFromBibliothequesList :", vc.receivedSelectedLibraryFromBibliothequesList )
}
This is the code that performs the Segue:
self.performSegue(withIdentifier: "BiblioToLoginSegue", sender: self)
What I need to implement is:
Redirect to the view (FirstViewController or SecondViewControler) that actually presented BibliothequesViewController.
The code above automatically redirects to FirstViewController whether it was the one that presented BibliothequesViewController or not.
I don't see which approach should I follow to implement this.
Should I use push instead of present in the FirstViewController&SecondViewControler?
The simplest way to teach a class to know something is to add a property:
class BibliothequesViewController {
...
var presentedBy: UIViewController?
...
}
to assign the property after the controller instantiation
let vc: BibliothequesViewController = storyboard.instantiateViewController(withIdentifier: "BibliothequesViewController") as! BibliothequesViewController
vc.presentedBy = self
and to use this property when the time comes.
I took #Roman's advice but I changed a couple of things.
CAVEAT: I am not sure this is the right approach but it worked for me.
BibliothequesViewController
class BibliothequesViewController: UIViewController {
static let sharedInstance = BibliothequesViewController()
var presentedBy: UIViewController?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if BibliothequesViewController.sharedInstance.presentedBy! is LoginViewController {
let vc = segue.destination as! LoginViewController
vc.receivedSelectedLibraryFromBibliothequesList = self.selectedLibrary
} else {
let vc = segue.destination as! ForgetPasswordViewController
vc.receivedSelectedLibraryFromBibliothequesList = self.selectedLibrary
}
}
#IBAction func onLibrarySelected(_ sender: Any) {
if BibliothequesViewController.sharedInstance.presentedBy! is LoginViewController {
self.performSegue(withIdentifier: "BiblioToLoginSegue", sender: self)
} else {
self.performSegue(withIdentifier: "biblioToPasswordForgottenSigue", sender: self)
}
}
}
LoginViewController
class LoginViewController: UIViewController {
#IBAction func onLibrariesButtonClicked(_ sender: Any) {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc: BibliothequesViewController = storyboard.instantiateViewController(withIdentifier: "BibliothequesViewController") as! BibliothequesViewController
BibliothequesViewController.sharedInstance.presentedBy=self
self.present(vc, animated: true, completion: nil)
}
}
ForgetPasswordViewController
class ForgetPasswordViewController: UIViewController {
#IBAction func onLibrariesButtonClicked(_ sender: Any) {
let storyboard: UIStoryboard = UIStoryboard(name: "Main", bundle: nil)
let vc: BibliothequesViewController = storyboard.instantiateViewController(withIdentifier: "BibliothequesViewController") as! BibliothequesViewController
BibliothequesViewController.sharedInstance.presentedBy=self
self.present(vc, animated: true, completion: nil)
}
}
NOTE: You have to create two Segues from BibliothequesViewController to LoginViewController and ForgetPasswordViewController with the identifiers mentioned in BibliothequesViewController.

Navigating One View Controller to Another using Swift 5 doesn't work

Okay guys, now that I have fixed this because of your help,
the error has gone.
but the page won't move to the 'requirementVC', so the button when i clicked, it just doesn't do anything.
#IBAction func buttonOK(_ sender: Any) {
let button = (self.storyboard?.instantiateViewController(withIdentifier: "RequirementsVC") as! requirementVC)
self.navigationController?.show(button, sender: nil)
}
Thankyou again, appriciate it!
You can do the following...
#IBAction func buttonOK(_ sender: Any) {
let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "RequirementsVC") as! requirementsVC
self.navigationController?.pushViewController(vc, animated: true)
}
Here Main is the name of the storyboard.
RequirementsVC should be storyboard id set in storyboard.
And requirementsVC should be the subclass of the UIViewController.
//Class name should always start with capital letter. So rename requirementsVC to "RequirementsVC"
class RequirementsVC: UIViewController {
//class body
}
just set your identifier and class of viewController you want to go on in this code :=
let addReminderVc = self.storyboard?.instantiateViewController(withIdentifier: "AddReminderVC") as! AddReminderVC
self.navigationController?.pushViewController(addReminderVc, animated: true)

how to enable the customview controller with view after dismiss Second viewcontroller in swift

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.

My show segue not using NavigationController

I am having problems segueing to my detail view, using Navigation Controller.
I was using a tableview, to display some exercises, and when you clicked the exercise you would seque into the detail view, embedded in nav controller
I have removed the Tableview, and added 3 buttons, each with its' own "show" segue to the detail view. It almost works, but it is now not using my Navigation controller, meaning that the view is just presented kind of like a modal presentation.
I have tried removing the segue on one button and replace with this action:
#IBAction func strengthButton(_ sender: UIButton) {
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let destination = storyboard.instantiateViewController(withIdentifier: "ExerciseViewController") as! ExerciseViewController
destination.componentaccessid = -1;
destination.openedFromUrl = false;
destination.exercise = self.strengthexercise
destination.exercisetype = .strength
self.navigationController?.present(destination, animated: true, completion: nil)
}
But that does exactly the same.
I have a prepare function:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let identifier = segue.identifier,
let destination = segue.destination as? ExerciseViewController{
destination.componentaccessid = -1;
destination.openedFromUrl = false;
switch identifier{
case "strengthsegue":
destination.exercise = self.strengthexercise
destination.exercisetype = .strength
case "rangesegue":
destination.exercise = self.rangeexercise
destination.exercisetype = .range
case "combinedsegue":
destination.exercise = self.combinedexercise
destination.exercisetype = .combined
default:
print("Nothing")
}
}
}
Try this
self.navigationController?.pushViewController(destination, animated: true)
In your code you are using,
self.navigationController?.present(destination, animated: true, completion: nil)
This will only present the UIViewController.
Instead use,
self.navigationController?.pushViewController(destination, animated: true)
to push the viewController in which the NavigationController is inherited.

Resources