segue if cant access all of them - swift

Hello i have problem because i have a var count that is += 1 when i press a button so, when i update de counter it doesnt function all the segues. for example if the count == 2, i want to acces count == 1 and count == 2
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "modos" {
if count == 1 {
if let destination = segue.destination as? ModosViewController {
destination.nnj1 = nombresJugadores[1]
}
}
if count == 2 {
if let destination = segue.destination as? ModosViewController {
destination.nnj2 = nombresJugadores[2]
}
}

If you truly want to be able to pass as many names as you want to your destination controller, your current approach won't work.
You need to have an array in your destination view controller that new names can be appended to. This way you can just call the index of each item in your destination controller. With your approach, you would have to create an infinite amount of nnj variables, which obviously isn't feasible.
So this would look something like this:
class ModosViewController: UIViewController {
var names: [String] = [String]()
...
}
Then what you can do is just change the prepareForSegue func to this:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if segue.identifier == "modos" {
if let destination = segue.destination as? ModosViewController {
destination.names = nombresJugadores
}
}
}
Because now you have an array of names in your origin that you pass onto the destination VC. Hope this helps.

Related

how do I refresh a childViewControler object when an action occurs on the parent viewControler

I have embedded a child ViewControler into my mainViewControler and it displays a graph.
the main view controller includes an input field and a save button.
I wish to have the graph in the childViewControler reload its data when the save button is taped.
the childViewControler includes a function
func refresh() {
fetchTransactionsAndCalculateTotals()
generateChartData()
setChart()}
that I would like to call. I have setup a segue from the main controller to the child controller,
enum Segues {
static let toInOutBar = "toInOutBars"
}
override func prepare(for segue: UIStoryboardSegue, sender: UIButton?) {
if segue.identifier == Segues.toInOutBar {
let destVC = segue.destination as! InOutBarViewController
destVC.refresh()
}
}
I am struggling to get further than this, I have tried to call this function from myUIButton action without success.
Thanks for any support
You should link an IBAction on the touchUpInside action of the button and get your child VC using the children property.
#IBAction func refreshClicked(_ sender: UIButton)
{
guard let vcChild = self.children.first as? InOutBarViewController else { return; }
vcChild.refresh()
}

How to use optional binding in switch statement in prepare(segue:)

In swift you can use a cool feature of the switch statement in prepare(segue:) to create cases based on the type of the destination view controller:
Example:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch segue.destination {
case let detailViewController as DetailViewController:
detailViewController.title = "DetailViewController"
}
case let otherViewController as OtherViewController:
otherViewController.title = "OtherViewController"
}
}
However, what if the segue is triggered by a split view controller, so the destination is a navigation controller, and what you really want to do is switch on the class of the navigation controller's top view controller?
I want to do something like this:
case let nav as UINavigationController,
let detailViewController = nav.topViewController as? DetailViewController:
//case code goes here
Where I have the same construct that I use in a multiple part if let optional binding.
That doesn't work. Instead, I have to do a rather painful construct like this:
case let nav as UINavigationController
where nav.topViewController is DetailViewController:
guard let detailViewController = nav.topViewController as? DetailViewController
else {
break
}
detailViewController.title = "DetailViewController"
That works, but it seems needlessly verbose, and obscures the intent. Is there a way to use a multi-part optional binding in a case of a switch statment like this in Swift 3?
I worked out a decent solution to this problem.
It involves doing some setup before the switch statement, and then using a tuple in the switch statement. Here's what that looks like:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
let dest = segue.destination
let navTopVC = (dest as? UINavigationController)?.topViewController
switch (dest, navTopVC) {
case (_, let top as VC1):
top.vc1Text = "Segue message for VC1"
case (_, let top as VC2):
top.vc2Text = "Segue message for VC2"
case (let dest as VC3, nil):
dest.vc3Text = "Segue message for VC3"
default:
break
}
}
You might find this extension useful…
extension UIStoryboardSegue {
var destinationNavTopViewController: UIViewController? {
return (destination as? UINavigationController)?.topViewController ?? destination
}
}
Then you can simply…
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch segue.destinationNavTopViewController {
case let detailViewController as? DetailViewController:
// case code goes here
}
Note that the ?? destination makes sure the return value is non-optional, and also allows it to work in places where the destination could also be a non-navigation controller.
I don't think there is a way to do this with switch and case, but you can do something closer to what you are looking for with if and case (Update: as Hamish pointed out, the case isn't even needed for this scenario) or just normal if let:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let nav = segue.destination as? UINavigationController,
let detailViewController = nav.topViewController as? DetailViewController {
detailViewController.title = "DetailViewController"
}
if let otherViewController? = segue.destination as? OtherViewController {
otherViewController.title = "OtherViewController"
}
}
Since your switch statement in this example isn't really going to ever be verified by the compiler as handling all cases (because you need to create a default case), there is no added benefit to using switch instead of just if let
Optional binding doesn't really lend itself to switches like you're trying to do.
I understanding the desire to use switches rather than simple if and if else, but it's a bit different conceptually from what switch is meant to do.
Anyway, here are the two options I use for most situations
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
switch segue.destination {
case is DetailViewController:
segue.destination.title = "DetailViewController"
case is OtherViewController:
segue.destination.title = "OtherViewController"
default:
break
}
}
or
func prepare(for segue: UIStoryboardSegue, sender: Any?) {
if let controller = seuge.destination as? DetailViewController {
controller.title = "DetailViewController"
}
else if let controller = seuge.destination as? OtherViewController {
controllercontroller.title = "OtherViewController"
}
}
In my opinion, you should use segue identifiers for controlling flow in this switch. But to answer your question, this should work for you.
switch (segue.destination as? UINavigationController)?.topViewController ?? segue.destination {
...
}
The thing is, according to grammar, you have only one pattern (in your case it is binding) per item in a case item list. Since you have only one item on the input but want to use two patterns, you either want to normalize input (which is in this case appropriate as you can see above) or extend item list (which is inappropriate in this case but I show an example below).
switch ((segue.destination as? UINavigationController)?.topViewController, segue.destination) {
case (let tvc, let vc) where (tvc ?? vc) is DetailViewController:
// TODO: If you await your DetailViewController in navigation or without.
break
case (let tvc as DetailViewController, _):
// TODO: If you await your DetailViewController in navigation but other vc is not in a navigation vc.
default:
fatalError()
}

how to pass Intergers between view controllers in swift

This is my code and it's not working. LightOrDark and LightDark are Integers and should be equal when the app changes views.
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if (segue.identifier == "LightSegue") {
if let MinigameView = segue.destinationViewController as? MinigameView {
self.LightOrDark = MinigameView.LightDark
}
}
}
self.LightOrDark = MinigameView.LightDark this statement sets MinigameView.LightDark to current class's LightOrDark.
You need to set LightDark of MinigameView so your code should be like,
MinigameView.LightDark = self.LightOrDark
And you should follow naming standard. variable or instance name should be start with lower case not upper case.
so your instance name should be lightOrDark and minigameView instead of LightOrDark and MinigameView.
Hope this will help :)
You need to set the destination viewcontroller property
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
guard let destVc = segue.destinationViewController as? MinigameView else {
return
}
destVc.LightOrDark = self.LightDark
}}
This is wrong: self.LightOrDark = MinigameView.LightDark. Change it to:
MinigameView.LightDark = self.LightOrDark

Sending Variables with a Segue

I am working on a simple iOS Swift app. The app has 2 view controllers and a button that has been programmed to segue to the other view controller like so:
#IBAction func pushMe(sender: AnyObject) {
self.performSegueWithIdentifier("changeIt", sender: nil)
}
The above works but I want to be able to save 2 variables from the current view controller and make them available to the view controller I am segueing to. So I did this:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "changeIt" {
var testVar1 = "Hello"
var testVar2 = "World"
}
}
In the view controller that I am segueing to I added:
var testVar1:String!
var testVar2:String!
The app works but as soon as I try to access testVar1 or testVar2, the app crashes. I am not sure why this isn't working as intended?
Because variables were not initialized, you omitted destination view controller. Use the code below
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject!) {
if segue.identifier == "changeIt" {
let dvc = segue.destinationViewController as! YourDestinationViewController
dvc.testVar1 = "Hello"
dvc.testVar2 = "World"
}
}
if segue.identifier == "changeIt" {
var testVar1 = "Hello"
var testVar2 = "World"
}
All you are doing here is making new, completely separate local variables called testVar1 and testVar2. They are not, by some miraculous wishful thinking, the same as the instance properties testVar1 and testVar2 belonging to the view controller you are segueing to. How can they be? That code never even mentions that view controller at all! If you want to set a property of a view controller, you need to talk to that view controller.
Think of it this way. Suppose the Dog class has a name property and you want to set a Dog instance's name. Do you do it by saying this?
let d = Dog()
let name = "Fido"
No! That creates a name, but it isn't the dog's name. You need to say this:
let d = Dog()
d.name = "Fido"
So in your code, you need to use the segue to get a reference to the destination view controller and set its properties.
You can solve it creating the variables on destination ViewController
class OtherViewController : UIViewController {
var testVar1 : String = ""
var testVar2 : String = ""
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
var message = "\(self.testVar1) \(self.testVar2)"
print(message)
}
}
The UIStoryboardSegue has a destinationViewController property. It's an instance to the end point view controller you want to reach. Then now you can do this:
class SourceViewController : UIViewController {
//...
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
//Some code before
var destination = segue.destinationViewController as! OtherViewController
destination.testVar1 = "Hello"
destination.testVar2 = "World"
//Some code after
}
}

Passing same object context 2 two separate view controllers

I have a managedObject that is being passed from 1 view controller to another the first pass works fine but when I try to pass the next object after the relationship has been set it doesn't send anything and comes back as either nil or if I try to use other methods comes back with a syntax error. The code I am using for the view controllers is as follows
View Controller 1, The first object set:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if let identifier = segue.identifier {
switch identifier {
case "popOver":
if let VC = segue.destinationViewController as? ClassDeckNameViewController
{
if let ppc = VC.popoverPresentationController {
VC.modalPresentationStyle = UIModalPresentationStyle.Popover
ppc.permittedArrowDirections = UIPopoverArrowDirection.Any
ppc.delegate = self
}
VC.classSave = (sender as! ClassSelection)
}
default: break
}
}
}
#IBAction func buttonPriest(sender: AnyObject) {
let entity = NSEntityDescription.entityForName("ClassSelection", inManagedObjectContext: classMOC!)
let newObject = ClassSelection(entity: entity!,insertIntoManagedObjectContext: classMOC)
newObject.classname = "Priest"
var error: NSError?
if let err = error {
println(err)
} else {
classMOC?.save(&error)
self.performSegueWithIdentifier("popOver", sender: newObject)
}
}
This passes the object without problem to the second view controller but this is the one that won't pass any further to the final presenting controller offering the user the final selections for their "Deck":
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "showCardSelection" {
let detailVC: CardSelectionViewController = segue.destinationViewController as! CardSelectionViewController
detailVC.passedDeckObject = (sender as! Deck)
}
}
#IBAction func enterButton(sender: AnyObject) {
let entityDescription = NSEntityDescription.entityForName("Deck",inManagedObjectContext: managedObjectContext!)
let storeDeck = Deck(entity: entityDescription!,insertIntoManagedObjectContext: managedObjectContext)
storeDeck.deckname = usersDeckName.text
storeDeck.classSelected = classSave!
var error: NSError?
managedObjectContext?.save(&error)
if let err = error {
status.text = err.localizedFailureReason
} else {
usersDeckName.text = ""
status.text = "Deck Saved"
self.performSegueWithIdentifier("showCardSelection", sender: storeDeck)
}
}
I made passedDeckObject a variable of type Deck? in the final view controller to set the final relationship methods I know I am doing something wrong but I am unsure what! Any help with this would be amazing!
This looks to be a misconfiguration issue where the segue is being triggered directly in the storyboard rather than calling your code. As such the sender is a button rather than the new entity instance you're expecting.
To fix, disconnect the segue in the storyboard and connect (if it isn't already) the button to your action method in the view controller.