Why two successive page opens with segue - swift

when I am selected button twice will open a new page.
//////
Main viewController
var Country = []
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
}
#IBAction func taxiAction(sender: AnyObject) {
let opt = ["1","2","3","4","5"]
Country = opt
performSegueWithIdentifier("viewPlaceSegu", sender: sender)
}
...
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
// get a reference to the second view controller
if segue.identifier == "viewPlaceSegu" {
if let secondViewController = segue.destinationViewController as? TableViewPlace {
// set a variable in the second view controller with the String to pass
secondViewController.tnt = Country as! [String]
}
}
}
////
http://i.stack.imgur.com/LKrN7.jpg
I tried so but didn't realize problem .
Does anyone know about this? :)

A likely cause is that you have connected the segue from the button to the new ViewController in the storyboard. When the button is pressed it will load the segue created in storyboard as well as the one created programatically.
If this is the cause then you would just need to delete the storyboard segue and create a new one from the ViewController rather than from the button.

Related

Value not passing between viewControllers

Struggling to get my viewControllers to send value from the main viewController to a second. I want it to happen on a button click, I'm going to get the value from the button and pass it to the new form. But it just isn't working.
Code for main ViewController
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
#IBAction func butClick(_ sender: UIButton) {
NSLog("Button Pressed : %#",[sender .currentTitle])
//var tt = [sender .currentTitle]
// Create the view controller
let vc = TimesTablesViewController(nibName: "TimesTablesViewController", bundle: nil)
vc.passedValue = "xx"
self.performSegue(withIdentifier: "pushSegue", sender: nil)
}
}
Code for second viewController called TimesTablesViewController:
class TimesTablesViewController: UIViewController {
#IBOutlet weak var titleLabel: UILabel!
var passedValue:String = ""
override func viewDidLoad() {
super.viewDidLoad()
titleLabel?.text = "\(passedValue) Times Table"
}
}
I've followed tutorials but can't seem to solve the problem! Thanks for any help!
Replace
self.performSegue(withIdentifier: "pushSegue", sender: nil)
with
self.present(vc,animated:true,completion:nil)
or ( if the current vc is inside a naigation )
self.navigationController?.pushViewController(vc,animated:true)
Using
self.performSegue(withIdentifier: "pushSegue", sender: nil)
is fit with storyboards not xibs and if this your case then you need to use the above line only inside the button action with implementing this method inside the source vc
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "pushSegue" {
if let nextViewController = segue.destination as? TimesTablesViewController{
nextViewController.passedValue = "xx"
}
}
}
I’m assuming that the new view controller is appearing, but you’re simply not seeing the data. If so, you’re evidently using storyboards. The TimesTablesViewController(nibName:bundle:) only works if you’re using XIB/NIBs and manually presenting new view controller.
If you’re really using storyboards, simplify your butClick method:
#IBAction func butClick(_ sender: UIButton) {
NSLog("Button Pressed")
performSegue(withIdentifier: "pushSegue", sender: self)
}
But implement prepare(for:sender:):
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let destination = segue.destination as? TimesTablesViewController {
destination.passedValue = "xx"
}
}
Assuming the above fixes your problem, I might suggest a further simplification. Notably, if your butClick(_:) method is really only calling performSegue, you can segue to this next scene without any #IBAction method at all:
remove butClick(_:) entirely;
remove the connection between the button and the butClick method in IB, on the “Connections Inspector” tab in the right panel; and
control-drag from the button previously hooked up to butClick(_:) to the scene for TimesTablesViewController.
That will simplify your code further.

Passing Data between view Controllers Using a segue from a view embedded in a navigation controller to a tabbarcontroller

I have two views that I would like to pass data from one view to the next. The first view is where I have the data that I would like to pass to the next view lets call it SourceViewController. However SourceViewController is embedded in a NavigationViewController and the secondViewController lets call it DestinationViewController is the firstView in a TabViewController.
I have tried to use the answer from this question and it fails to go past navigation view it just skips the whole logic.
This is my code :
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "loginSuccessSugue") {
if let tab = self.presentingViewController as? UITabBarController,
let nav = tab.viewControllers?[0] as? UINavigationController,
let destinationVC = nav.viewControllers.first as? HomeViewController {
destinationVC.currentBalance = serviceBalance
}
}
}
This is the HomeViewController:
class HomeViewController: UIViewController , UITableViewDelegate,UITableViewDataSource, UICircularProgressRingDelegate{
var currentBalance = 0.0
override func viewDidLoad() {
super.viewDidLoad()
circularBalance.maxValue = CGFloat(currentBalance)
print(currentBalance)
}
override func viewDidAppear(_ animated: Bool) {
print(currentBalance)
circularBalance.setProgress(value: CGFloat(currentBalance), animationDuration: 3)
}
}
This is how the storyboard looks like:
This is my view controller where you can check that I am sending 5 to tabbar first viewcontroller:
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
self.performSegue(withIdentifier: "segueIdentifier", sender: self)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let barViewControllers = segue.destination as! UITabBarController
let destinationNv = barViewControllers.viewControllers?[0] as! UINavigationController
let destinationViewController = destinationNv.viewControllers[0] as! FirstViewController
destinationViewController.currentBalance = 5
}
}
Now You can check my firstview controller where you can check that what value we are getting.
class FirstViewController: UIViewController {
var currentBalance = 0
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
print(currentBalance)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Now, You can check my console and storyboard:
From Apple's UIViewController docs:
var presentingViewController: UIViewController?
The view controller that presented this view controller.
Which would work great for you, ** IF ** you were trying to go back in your navigational hierarchy, as did the guy in the SO post you referenced.
You are trying cast the VC THAT PRESENTED SOURCEVIEWCONTROLLER of your SourceViewController as a UITabBarController, which fails miserably, and is why you never hit a breakpoint inside your nested if let's.
If we look the next variable down from this in the docs we can see something that will take us forward to the UIViewController we are presenting:
var presentedViewController: UIViewController?
The view controller that is presented by this view controller, or one
of its ancestors in the view controller hierarchy.
So now to go over the code you need to solve your predicament. I'll give you the same code you posted, but fixing the tense of my verbs in the comments:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "loginSuccessSugue") {
//ing -> ed
if let tab = self.presentingViewController as? UITabBarController,
let nav = tab.viewControllers?[0] as? UINavigationController,
let destinationVC = nav.viewControllers.first as? HomeViewController {
destinationVC.currentBalance = serviceBalance
}
}
Isn't it frustrating when the English language tricks you up more than swift?
EDIT:
Since you are passing the data in prepareForSegue: you will actually want to get the UITabBarController from segue.destination. And since the the UITabBarController's ViewControllers property will be nil or empty in prepare for segue. This is a bad approach for passing the data.
You may need to create custom subclass of UITabBarController, pass it the variable, and then pass that data to its viewControllers in viewDidLoad.
class MyTabBarController: UITabBarController {
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
var serviceBalance : Double?
override func viewDidLoad() {
super.viewDidLoad()
//Make sure vc is not null or empty before continuing.
guard let vcs = viewControllers, !vcs.isEmpty else {
return
}
if let navVC = vcs[0] as? UINavigationController, let destinationVC = navVC.viewControllers[0] as? UIViewController {
destinationVC.serviceBalance = destinationVC
}
}
}
Updated prepareForSegue:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let tabBarVC = segue.destination as? MyTabBarController {
tabBarVC.serviceBalance = serviceBalance
}
}
Don't forget to change the UITabBarController's class in the identity inspector of storyboard to MyTabBarController
You need to change if() condition code.
Use below code will get your HomeViewController in destination of segue.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if (segue.identifier == "loginSuccessSugue") {
if let destinationVC = segue.destination as? HomeViewController {
destinationVC.currentBalance = serviceBalance
}
}
}
As in segue.destination you will get your HomeViewController so no need to get it from Tab + Navigation stack.
Edit:
let destinationVC = segue.destination as? HomeViewController
Print(destinationVC)
Hope this solution will helps!

Accessing methods, actions and/or outlets from other controllers with swift

I'm working on a macOS project where I have a split view containing 2 other ViewControllers and I can't figure out how to access the ViewControllers from my primary window's ViewController.
this is the setup:
Basically what I'm trying to do is use the Button in my ViewController on the top-left to access the Label in my SectionController on the right, which is embedded in my split view.
Since I can't create an IBAction or IBOutlet for a control in a different ViewController, I can't figure out how to get these to be connected. My current workaround has been to have a property on my AppDelegate and then access the main shared application delegate, but that feels hacky and won't scale. I'm completely lost as to how to proceed. I'm ok with using a function to pass data or whatever to the other ViewController(s).
I'm using Swift 4 with Xcode 9 (beta).
Any ideas?
Of course you can't create IBAction or IBOutlet for a control in a different ViewController!!
But simply each view controller in the hierarchy has a reference for its child view controllers.
Method 1:
#IBAction func buttonTapped(_ sender: Any) {
let splitViewController = self.childViewControllers[0] as! YourSplitViewController
let targetViewController = splitViewController.childViewControllers[0] as! YourTargetViewController
targetViewController.label.text = "Whatever!"
}
Method 2:
It may be better if you took a reference for each child controller in your "prepare for segue" method
ContainerViewController:
var mySplitViewController: YourSplitViewController?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "splitViewSegue" {
self.mySplitViewController = segue.destination as! YourSplitViewController
}
}
YourSplitViewController:
var aViewController: YourFirstViewController?
var bViewController: YourSecondViewController?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "aViewSegue" {
self.aViewController = segue.destination as! YourFirstViewController
} else if segue.identifier == "bViewSegue" {
self.bViewController = segue.destination as! YourSecondViewController
}
}
So you can access it like that in your container view controller:
#IBAction func buttonTapped(_ sender: Any) {
self.mySplitViewController.firstViewController.label.text = "Whatever!"
}

How to programmatically seque to multiple view controllers from a button

I have a view controller with a lot (36) of buttons, and I want each of these buttons to segue to a particular view controller based on a variable that was set earlier in the program. In other words, any button could potentially go to 15 different view controllers based on a variable that was sent to the viewcontroller containing the buttons...
I think I can make this work if I click and drag each button to every viewcontroller... but it seems silly and messy.
I tried doing something like this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if variable == "Whatever" {
let send = segue.destination as! AViewController
send.variablesent = (sender as! UIButton).title(for: .normal)!}
}
But this only works if I click and drag the button in the storyboard to the "AViewController".
Any help is appreciated, thanks!!
For that you can make segue from SourceViewController to DestinationViewController instead of from Button to Controller, After that when you call perfromSegue in your button action then pass button reference as sender in perfromSegue call.
#IBAction func buttonAction(_ sender: UIButton) {
self.performSegue(withIdentifier: "segueIdentifier", sender: sender)
}
Now in prepareForSegue cast sender to UIButton and set title according to it.
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if variable == "Whatever" {
let send = segue.destination as! AViewController
if let button = sender as? UIButton {
send.variablesent = button.titleLabel?.text ?? "Default value"
}
}
}

How to identify if a scene has been opened by a certain segue in Swift?

I have a scene which I open with this segue.
//pass all retrived info from signup field over to the login scene to facilitate user experience
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "showLoginController") {
let svc = segue.destinationViewController as! LoginController;
print("pass data over to next viewcontroller")
}
}
This segue goes back to the Login screen where I want to set some values. However when the Login screen has not been loaded by segue "showLoginController", some fields should be empty.
How can I identify if LoginScene has been opened by a certain segue and set values accordingly?
In your LoginController view controller add this:
var fromSegue = false
And in prepareForSegue:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if (segue.identifier == "showLoginController") {
let svc = segue.destinationViewController as! LoginController;
svc.fromSegue = true
print("pass data over to next viewcontroller")
}
}
And then in your LoginController you can check fromSegue.
You can know the segue from the previous scene, in the sender scene, implement prepareForSegue() method to detect the sender