I've looked around many threads and haven't benefitted with my issue. My issue lies in my 3rd VC where the user taps an 'Edit UIBarButtonItem' which segues them to the 4th VC. The segue ID is correct and both VC's 3 and 4 are static table VC's, but 4 is embedded in a nav controller and 3 isn't. i want the data in the textfields in VC 3 to be 'copied' to the almost identical looking textfields in VC 4, so that changes can be made by the user and updated. When i type cast my destination segue as the 4th VC inside prepareForSegue, it returns nil and the instance of data inside doesn't get moved to the 4th VC since 'if let' is being used. Why does it return nil? I've looked up the life cycle of segues too but haven't learnt much, all other VC's are fine.
I have tried both below and both return nil for VC 4
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "EditSegue" {
print("correct segue name")
if let editVC: EditTableViewController = segue.destinationViewController as? EditTableViewController {
editVC.instanceOfData = self.instanceOfData //instance of data in 4th VC = instanceOfData in 3rd VC
}
}
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let editVC = segue.destinationViewController as? EditTableViewController
if segue.identifier == "EditSegue" {
editVC.instanceOfData = self.instanceOfData
}
}
I could be doing something obviously wrong which i haven't come across yet! I've successfully transferred data between two VC's before but not when instances have been passed around between VC's.
Any help is appreciated, thanks.
Related
my problem is that when i switch to an another ViewController, my variables of the previous VC call are reset so i can't do what i want after
#IBAction func BackBtn(_ sender: Any) {
self.nbrQst = 10
self.Switch1A = 2
performSegue(withIdentifier: "Numero", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "Numero" {
let vc = segue.destination as! ViewController
vc.nbrQt = nbrQst
}
if segue.identifier == "Numero" {
let vcNv = segue.destination as! ViewController
vcNv.Switch1 = Switch1A
}
}
below the way that i send information from my Lvl1 file to the lvl selector file to add a if else for unblocks the lvl
#IBAction func BackBtn(_ sender: Any) {
self.nbrQst = 10
self.Switch1A = 2
performSegue(withIdentifier: "Numero", sender: self)
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let vc = segue.destination as! ViewController
vc.nbrQt = nbrQst
vc.Switch1 += 2
}
that's the second ViewController who send the number to the first one, and i want that the first one remember the number and add them up each time I press the button that sends the numbers
Let's call "Selector VC" the main VC.
The reason why those numbers reset in main VC is that when you press the "BackBtn", you're not actually going back to main VC, you're creating a new main VC and going there (because you did performSegue(withIdentifier: "Numero", sender: self) in BackBtn function, performSegue always takes you to a new VC rather than taking you back). The new main VC has all those fields starting from an initial number (I assume initially they're zero).
What you want to do is to go BACK, not forward. Depending on how you went to the level VC from main VC, you have different ways of going back to main VC.
If you're pushing everything onto a navigation controller, then you can go back by:
self.navigationController?.popToRootViewController(animated: true)
If you're presenting everything modally, you can go back by
self.dismiss(animated: true, completion: nil)
You said, you want to update the value in main VC so that you can block/unblock next level. A very standard way to achieve this is via delegate, please Google this ("delegates in Swift") and follow their tutorials there.
I strongly recommend that you take an online course on swift development before you go ahead and develop your own app, because you could potentially do a lot of things wrong and waste a lot of your time trying to get an answer from Stack Overflow.
I have my UIViewController, which is a person's profile page, it displays their name and picture. Within that UIViewController I have a UIContainerView that displays a static UITableView. I'm having a little trouble updating the cells of the table when the profile page loads. Here's my storyboard:
I have tried the following, within my UIViewController.
I created an outlet to my UIView and passed the person object to it.
In my UIView I called the segue to pass the object to the UITableViewController and from there I was going to update some labels.
func prepareForSegue(segue: UIStoryboardSegue!, sender: Any?){
if segue.identifier == "containerSegue"{
let statsTable = segue.destination as! CollectionTableViewController
statsTable.currentPerson = currentPerson
}
}
My Segue is never called though. I have moved it to the main UIViewController in case it should be called from there, but again not called. What am I doing wrong with this approach?
Assuming you have set the Segue Identifier to "containerSegue" you should get it in your "Stats" view controller.
Are you using Swift 3? It's possible you just have the func definition wrong:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "containerSegue" {
let statsTable = segue.destination as! CollectionTableViewController
statsTable.currentPerson = currentPerson
}
}
That should work.
Up to date Xcode/Swift/iOS.
I have a Master VC (called StartVC) that contains a Child VC (called TopBarVC) via and embedded segue. The Child VC contains a button, that, when pressed, modally segues to a 3rd VC (called CategoryPickerOverlayVC) (the view in this VC serves as a dropdown box for picking a category).
#IBAction func CategoryFilterButtonPressed(_ sender: Any) {
performSegue(withIdentifier: "toCategoryPickerOverlay", sender: self)
}
When an option is selected from the dropdown box, which itself is composed of three buttons, the title of the selected button should be used to replace the title text of the button in the Child VC.
In the Master VC, I use prepareforsegue to store a reference to the Child VC in a variable - "topBarReference" - at the moment when the embed segue takes place.
var topBarReference: TopBarVC?
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "TopBarPane"{
topBarReference = segue.destination as? TopBarVC
}
}
Then, in the 3rd VC, when I click on one of the button options in the dropdown box, the button title is sent via a prepareforsegue to update the button in the Child VC (via "topBarReference").
if segue.identifier == "unwindToStartVC"{
let vc = segue.destination as! StartVC
vc.topBarReference?.filterButtonText = ((sender as! UIButton).titleLabel?.text)!
}
The 3rd VC then unwind segues back to the Master VC. I should add that when the button in the Child VC is changed, a variable (filterButtonText) in Child VC is first set with the title text and then this variable is then used to set the button title text via the viewDidAppear method of Child VC.
When using the debugger, I also note that viewDidAppear in the Master VC does not seem to execute after unwinding (I placed a diagnostic print-to-console in viewDidAppear and nothing prints after the unwind segue). I realise this would explain the button not getting updated but I've got no idea why viewDidAppear does not run.
I have also tried using a delegate protocol and instantiateViewController(withString:) to no avail. All of the methods produce the same result, which is that the button in the Child VC does not get updated. No errors are shown. Everything else happens as expected.
Any ideas as to what I am doing wrong?
Do you mean something like this?
If so, the solution I used was very simple: the third VC uses prepareForSegue to set a property of the embedded VC, and the embedded VC picks up that property in the unwind method.
In my implementation, the three view controllers are called ViewController, ChildViewController, and ThirdViewController. This is the entire code (everything else is configured in the storyboard):
class ChildViewController: UIViewController {
#IBOutlet weak var theButton: UIButton!
var buttonTitle : String?
#IBAction func unwind(_:UIStoryboardSegue) {
self.theButton.setTitle(self.buttonTitle, for: .normal)
}
}
class ThirdViewController: UIViewController {
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
(segue.destination as! ChildViewController).buttonTitle = (sender as! UIButton).currentTitle
}
}
Ok, so I have found that my original code works fine bar one line in the prepareforsegue of the Child VC. If I change that prepareforsegue from:
if segue.identifier == "unwindToStartVC"{
let vc = segue.destination as! StartVC
vc.topBarReference?.CategoryFilterButton.titleLabel?.text = ((sender as! UIButton).titleLabel?.text)!
}
to this:
if segue.identifier == "unwindToStartVC"{
let vc = segue.destination as! StartVC
vc.topBarReference?.CategoryFilterButton.setTitle((sender as! UIButton).titleLabel?.text, for: .normal)
}
it works just fine. The use of the .setTitle method seems to make a difference although I am not sure why.
Thanks to Matt for giving me the idea to change it to that. Matt's method did work when i tried it, although, as I am unwinding to the Master VC and not the Child VC, I had to edit the code accordingly, in terms of where I placed it.
As my little "discovery" equates to the smallest change to the original code, I'll mark this as the answer.
Thanks to all for taking the time to respond!
I am using for the first time the Unwind Segue approach. I have multiple view controllers as can be seen in the picture below (a few of them shown of course). In the Edit Profile I have a Done button. Once clicked I trigger an IBAction that triggers an unwind segue.
Here is the code for the Done button in the nav bar:
#IBAction func unwindToMainViews(sender: UIStoryboardSegue) {
//let sourceViewController = sender.sourceViewController
self.performSegueWithIdentifier("unwindToMainSegue", sender: self)
}
and in the
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!)
I am doing the following to pass data from Edit Profile back to Home View
if (segue.identifier == "unwindToMainSegue") {
// pass data to next view
let tabCtrl = segue.destinationViewController as! UITabBarController
let destinationVC = tabCtrl.viewControllers![0] as! HomeViewController
destinationVC.userObject = self.userObject;
}
When segue identifier is matched and code is executed (to transfer userObject from this controller to another), it triggers the error:
Could not cast value of type 'app.EditProfileViewController' (0x100b99d80) to 'UITabBarController' (0x104a1d030).
How can this error be fixed? I am surprised since i am casting to UITabBarController so thought it should work.
You don't return to the UITabBarController in an unwind segue. You return to the ViewController that triggered the original segue, or one if its ancestors.
As #jlehr stated in the comments:
Unwind segues don't return to anything; they dismiss any pushed and
presented view controllers between the source and destination view
controller. The destination is wherever the implementation of the
unwind method is found, regardless of how the source view controller
was presented.
To unwind to the viewController that triggered the original segue, you need to implement the #IBAction func returnToHere(segue: UIStoryboardSegue) function in the viewController you want to return to.
Then when you set up your Done button by dragging to the Exit icon, you select returnToHere from the pop-up.
To pass data back to the sourceViewController, give your unwind segue an identifier such as "unwindToSource", then override prepareForSegue in the viewController you are returning from:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "unwindToSource" {
let dvc = segue.destinationViewController as! SourceViewController
dvc.userObject = self.userObject
}
}
I am very new to the swift language and am trying to make an app that would do some basic calculations. The problem I am running into is that I want to use the values from an array that is declared in one viewcontroller in another viewcontroller to do calculations.
I declare the array in the first viewcontroller like this:
var array2 = [Double]()
And then I have no idea how to access this in the second view controller. I have tried looking at previous questions as well as online tutorials and have had no success.
Any help is greatly appreciated. Thank you in advance.
in VC2 create global var array2 = [Double]()
add following override func to body of VC1
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
let DVC = segue.destinationViewController as! ViewController2 //replace ViewController2 with the name of your 2nd VC
DVC.array2 = array2
}
Overall, what you are doing is telling VC1 to copy VC1's array2 to VC2's array2, before the segue happens.
As your app becomes more complex, if your VC1 has more than 1 segue...meaning can go to multiple different VC's...you'll need to change your prepareForSegue so that it takes into account for this.
One way to do this is to change it to
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "SegueIdentifier you give to that particular segue in identityInspector" {
let DVC = segue.destinationViewController as! ViewController2 //replace ViewController2 with the name of your 2nd VC
DVC.array2 = array2
}
}