Access UITabBarController to assign action via Storyboards - ios

Without storyboards, I can simply assign the UITabBarController.delegate = self (in AppDelegate, for example). This lets me handle what happens when a UITabBarButton on the UITabBar is pressed.
However, I'm now using storyboards, where my UIViewController is contained in a UINavigationController, which is contained in a UITabBarController.
What's the best way to access this parent UITabBarController in code? I'd like to do this so I can assign a delegate to it. When the user presses a button in the UITabBar, I want to take an action in my contained UIViewController.

self.navigationController?.tabBarController

Related

Navigate to UIViewController from a UIView

My app header is currently a full width, 65pt height UIView which I then use as a generic header for all pages.
class AppHeader: UIView {
...
}
Then, in my Main.storyboard I have a UIViewController with a View from the object library which has its class specified as AppHeader.
My AppHeader (UIView) has multiple buttons which should, if clicked, take you to from the page/controller you're currently on to another.
From the AppHeader class I do not have access to use the present method to show another controller as its not within scope.
Here is my AppHeader.xib:
How can I resolve this?
This is very bad behaviour, you should not use a UIView as a header. You should add a Navigation View Controller as the first view controller of your app. Navigation view controller has the navigation bar where you can put the buttons you want there. From that ones, you will be able to push or present other view controllers.
Check the official documentation: https://developer.apple.com/library/content/documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/NavigationControllers.html
Make your AppHeader view a custom subclass of UIView if it isn't already. Wire the actions on the button to IBAction methods in the view.
Create a protocol AppHeaderDelegateProtocol. Give your AppHeader class a weak delegate property. Define methods in that protocol that let the AppHeader notify it's owning view controller about button presses.
Implement your AppHeaderDelegateProtocol in view controllers that will contain instances of AppHeader.
Connect the delegate property to each instance of AppHeader's owning view controller.
That should do it.
You can create a protocol - call it AppHeaderDelegate or something - and set up your other viewControllers to adopt that protocol. You could define functions to let your delegate know that a certain button was pressed, and your delegate viewController can react to that by presenting the correct view controller.
Apple's docs on protocols here.
Alternatively, you can use NotificationCenter to broadcast notifications to let subscribers know that a certain button was pressed, and have your viewControllers listening for these notifications and reacting to them accordingly. You have to manage when classes start/stop listening, though, as you may have several objects trying to react to a single notification.

Using storyboarding in xCode how can I change the value of a label from a different view?

I'm writing an app that uses storyboarding and I want to update the labels in one view by clicking a button in a previous view.
_label.text = variable1;
is the line I would use to change the value of label, which is in the next view, when I click the button. Using this method I can easily change labels in the same view as the button but it does nothing when I go to the next view and see empty labels.
I've tried looking everywhere and found similar issues but couldn't find anything that worked for me so any solution would be very appreciated!
Unfortunately, it is not possible to connect IBOutlets between different scenes in storyboard.
It is difficult to suggest some precise solution because you have to provide more details about the setup which you have. Still, it is possible to outline some possible solutions:
Using prepareForSegue
If the view controller which you want to modify appears after the segue is performed you can customise its appearance in prepareForSegue function.
Using delegation
You can assign the view controller which wants to modify another view controller as its delegate. For example, if ViewController1 wants to modify ViewController2:
#interface ViewController1: UIViewController {}
#property (nonatomic,weak) ViewController2 *controllerThatIWantToModify;
with such setup you can call:
self.controllerThatIWantToModify.label.text = variable1;
You use storyboards, so there must be a segue from your first viewController (with the button) to your second (with labels in it).
If it is the case, you can set up the labels of the second view controller from the prepareForSegue method of your first view controller.
This method is called with a segue object which has a destinationViewController property which is your second view controller.
If you have several segue from this viewController, you should check if it is the right segue and then set it up.
To do that you need to set up outlets that gives you access to the labels from the viewController.
Then you can either write a setUpLabelsWith:(NSString)text1 ... method in your view controller, or directly access the outlets from the first view controller (supposing their are not private).
Yes this supposes your second view controller has a custom class.

UINavigationController issue

In my app I'm switching between UIViewController using Navigation Controller and the Action Segue "Show". But for example if I write something in a UITextView and I return in that UIViewController the text is deleted. How I can keep the information ? Like in the UITabBarController.
You can create uiviewcontroller objects in app delegate and use that objects for swapping between view controllers. In current scenario, whenever you load same view controller again, it is created as fresh object so UITextView is initialized again, so text you entered will not be saved.
Or you can save value of UITextView in global variable or NSUserDefaults on viewwilldisappear() and initialize again in viewwillappear()
U can use restoration ID in the IB for that particular UITextView.

Storyboards, UITabBarController and SWRevealViewController

I have a storyboard that uses a UITabBarController with 3 tabs.
I want to use SWRevealViewController to add the sliding menu functionality.
Opening the menu will slide the hole UITabBarController.
Did anyone managed to implement this kind of behaviour with storyboards UITabBarController and SWRevealViewController?
Thank you
Managed to integrate it. Below are the steps to do it:
Add a new UIViewController to the storyboard.
Remove the content view from the newly added UIViewController
Make sure "Is Initial View Controller" is checked in IB for the newly added UIViewController
Set the custom class for the newly added UIViewController to SWRevealViewController
Connect it to a view controller that you intend to be the rear view controller - give the segue "sw_rear" identifier in IB. This must be a reveal controller segue type.
Connect it to the UITabBarController - give the segue "sw_front" identifier in IB. This must be a reveal controller segue type.
You should use a navigation controller before tab bar controller(sw_front > navigation controller > tab bar controller).
gfdx answered his own question, but make sure to also look at this tutorial for more insight on how to hook up everything else correctly.
Because I'm using Core Data and I was told that calling
[[NSApp delegate]managedObjectContext];
is not a good idea, I pass in my data controller class to the views in AppDelegate.m. Since I'm now using the SWRevealViewController instead of my subclass of UITabBarController, I had to make some modifications.
SWRevealViewController performs some interesting behaviors on load, one of which is loading the dependent view controllers by calling the segues. Be aware that if you make changes in your subclassed prepareForSegue:sender: method, make sure to always, always call the super's method, otherwise you'll end up with a black, blank application.

Reuse childs from custom UIVIewController using storyboard

I have a storyboard with a navigation controller that leads to an UIVIewController that I want to reuse. That UIVIewController has a ParentUIViewController that has all the basic functionalities for all the UIVIewControllers that I am reusing.
Currently I am copying and pasting (meh) and then I change the class of the UIViewController to the ChildUIVIewController that I want to use (ChildUIViewController extends ParentUIViewController).
But this sounds like a bad solution. Everytime I want to change the ParentViewController visually I need to update, manually, all other ChildViewControllers.
I have tried to create a xib for the ParentViewController but the xib isn't loaded because I need a xib with the name of the ChildViewController. I have created it and then said the class is the ParentViewController but it crashes in the segue.
EDIT
I have created an example of the status of my problem
https://github.com/tiagoalmeida/storyboardexample
Note that the ParentViewController has a set of logic way more complicated that is not illustrated there. Also note that I am also using a TableView. I hope that this can illustrate the problem.
Keep the logic on the parentViewController and the UI Part on the child UIViewControllers. If you need to create a new UIViewController, you will create a child that will have a corresponding XIB (or get rid of XIBs and create the interface by hand).
Have you considered looping back into the same UIViewController via a "phantom button"?
Have a look at this: UIStoryboard Power Drill, Batteries included
Essentially you can drag a Bar Button Item into the little black bar under the View Controller in Storyboard (the 1 with View Controller, First Responder, and Exit icons; sorry, I don't recall what this is called exactly), then you can control+drag from that button back into the UIViewController for a Push segue. This should create a loop segue in your Storyboard. All you need to do next is give that segue an identifier, programmatically call it from your code using [self performSegueWithIdentifier:], then implement -(void)prepareForSegue: and use [segue destinationViewController] to conditionally set the title and perhaps some flags so you can identify when to use different kinds of fetches (or other code variations) in the same Class code.

Resources