Sending data between ViewControllers without segues - ios

Is there a way to send data between ViewControllers without using segues?
Specifically I have two ViewControllers embedded in a TabBarViewController. One is called PlayingCardViewController and the other is called HighScoreViewController. I want to pass a class HighScore from PlayingCardViewController to HighScoreViewController. I want to transfer the data from PlayingCardViewController as soon as I press the redeal button in PlayingCardViewController but I don't want to transition to the HighScoreViewController as that would be jarring for the player.
I thought about using segues and holding the HighScores in an array and passing that to all the VC's that PlayingCardViewController is connected to but I realized that that seems overly complicated and there must be a simpler way to pass the data upon hitting the redeal button.
Some relevant links
Passing Data between View Controllers

I'm just going to do this with bullet points:
You could implement a custom tab bar controller (your own UITabBarController subclass), and use this instead of a basic UITabBarController.
Your PlayingCardViewController could have its own delegate protocol/property.
The delegate protocol could define a method like playingCardVC:didSetHighScore:.
Your tab bar controller would be the PlayingCardViewController's delegate.
The tab bar controller could keep a reference to the HighScoreViewController.
When your tab bar controller gets the playingCardVC:didSetHighScore:, it could pass whatever you want to your HighScoreViewController.

Related

Call function in ViewController after RelationshipSegue

I am having a multiple UIViewController embedded in a UITabbarController.
These are connected by Relationship Segues.
The starting point, VC1 initially loads data and is then processed to a "detail" view.
Whenever I change tabs and go back to VC1, the application gets stuck, as viewDidLoad is not called.
Is there a way to trigger a function each time VC1 is segued to?
the application gets stuck, as viewDidLoad is not called
The application is not stuck. It is working perfectly. viewDidLoad is called when a view controller is created and loads its view. That only happens once in the life of the view controller. When you leave a view controller and come back to it, it is still there (i.e. it is not being created from scratch), so naturally viewDidLoad is not called.
If your goal is to hear about the fact that the tab bar controller is switching to VC1, give the tab bar controller a delegate and implement tabBarController(_:didSelect:) or similar.
Even better, configure things so that there is no need to do this. If there is common data that is accessed by both view controllers, architect things so that a view controller sends new data up to a data controller and the data controller broadcasts news of the change down to all view controllers that need to know this.

How to use Storyboard view controllers without reloading each time they show

I have several UIViewControllers in a Storyboard.
I'm not using a Navigation controller, just simple Segues to show them and to unwind.
However each time show/unwind a View, it completely reloads.
I would like it to "load" only the first time it's shown, and then
hide/show as I move to other View Controllers.
How can this be done using Storyboards and Swift 2?
Assuming that you'd always have a base (menu or something) UIViewController, I'd use UINavigationController and just keep optional references to created UIViewControllers in this menu controller, like :
var firstViewController : VC1?
var secondViewController : VC2?
You should create a function to get those view controllers like:
func getVC1Instance() {
return firstViewController ?? firstViewController = self.storyboard.instantiateViewControllerWithIdentifier("VC1Identifier")
}
Then, when you click a button that should take you to VC1 for example, you should do
self.navigationController?.pushViewController(getVC1Instance())
I don't know what your use case is, but I really don't recommend retaining UIViewControllers that aren't shown on the screen. If you need to persist their state, just use NSUserDefaults / Singleton pattern to store the data like text typed into some textfields and just use them on viewDidLoad.

Detect Child UIViewController being popped

I'm sure this will be a simple answer, maybe a method I'm missing to implement. Here goes:
In my Controller1 I use a pushViewController to push a new view Controller2 onto my view stack. I'm getting a back button.
Now, when Back button is pressed in my Controller1 I want to be able to detect that Controller2 is being popped and we're back in Controller1. Makes sense?
I was trying to do that with ViewDidAppear, but I'm not sure how to detect a popped controller. There are other answers here but they all show examples in Controller2 on viewWillDisappear
How would I do that in Swift?
Without knowing more you should pass a reference of the first controller to the second controller so that the second controller can tell the first when it is done (this is a simple delegate relationship, it could also be implemented using a block / closure).
Ideally the first controller should be responsible for dismissing the second controller, either when it gets this callback or, more appropriately, directly when the 'dismiss' button is tapped.

Can I send performSegueWithIdentifier: to anything other than self?

I have a category on UIViewController that deals with errors coming from my networking layer. If I get an authentication error in response to a network call, I want to perform an unwind segue which takes me back to my LoginViewController.
However, I don't want to have to add the appropriate unwind segue to every single view controller in my Storyboard. Can I simply declare the unwind segue in the UITabBarController that is at the "top" of my view controller navigation, and then say
[self.tabBarController performSegueWithIdentifier:#"UnwindToLoginSegueIdentifier" sender:self]
... from inside my UIViewController+ErrorHandling category?
No, you can't do that. The unwind segue has to come from the controller you're unwinding from, and all segues need to be connected from a particular instance in the storyboard. The login view controller really should be one that's presented modally, not be one of the tabs, since you only need it briefly, then it should go away. If you set up your app that way, you can present and dismiss it from any controller (present it without animation from the controller in the first tab, if that's what you want the user to see when the app launches). You'll still have to have code in every controller to do that, unless you make a common base controller with that functionality that all the other controllers inherit from.

About passing data between view controllers with delegate

FIRST SCENARIO:
I have two view controllers
VC1 has a button, and a label
VC2 has a button, and a text field
theres a modal segue between VC1 -> VC2
when I run this segue, we set VC1, as the delegate for VC2.
We go to VC2, fill out the text field, hit the button, and VC2 is dismissed.
some delegated method is run on VC1, and VC1.label is filled in.
question: is there any way to do this without dismissing VC2.. for example, if VC2.button just modal segues us back, or slides us back to VC1 im assuming it re initializes the viewcontroller and the label wont be changed. do you always have to dismiss the view controller
SCENARIO 2:
again, two view controllers.
this time its reversed.. so i have
VC1 with a textfield and a button
VC2 with a label and a button
soo now we fill out VC1, and we expect it to show up on VC2. But without a segue, they have no relationship. is there any way to pass data between VCs using delegation without one initial segue? Is this segue requirement to use delegation something specific to view controllers? Im assuming it is because in other cases we just instantiate objects, and use their delegate methods. but with view controllers we want to reference one that is already created, and not instantiate a second one.
note: im using story boards
1) You could do it without dismissing VC2, but it's not a good idea. You don't want to segue "back" to one, because, as you surmised, you're actually creating a new instance of VC1, and then if you segue again to VC2, you're creating a new instance of that too. You will keep piling up more and more instance of the two controllers and none will ever be deallocated.
2) Again, your instincts are correct -- you need to somehow get a reference to the instance of VC2 that your putting on screen in order to set yourself as delegate. You don't have to have a segue to do that, you could create the second controller in code and do a manual push or presentViewController, but that's functionally, the same as doing a segue.
Sorry, dont fully understand what you want .. but here is my take.
FIRST SCENARIO:
Why would you need to update the view that isnt on screen ?
Just update in viewWillAppear.
Otherwise you can have the delegate update it when you finish editing that textfield.
SCENARIO 2:
You need a link between the view controllers, use segues makes easy, set as delegate and pass along the info. Why make it harder than it needs to be
Many things have delegates, textfields etc, you are just saying this class / obj will do something for something else.
There are many youTubes about delegates, ie
http://www.youtube.com/watch?v=eNmZEXNQheE
For more info see this stack post - it covers everything you need to know
Passing Data between View Controllers

Resources