using viewForHeaderInSection method in iOS application - ios

I have a grouped UITableView with multiple segments. I would like to have a button below each segment in the footer that when pushed would take the user to a different view controller (with some options - the data-model to be loaded in the destination VC). The two ViewControllers in question are managed by a UINavigationController.
I am not sure what the best way to achieve this is...
I have tried:
Creating each UIView (with the button) in IB and trying to add the view to a section footer there. I do not think this is possible.
Creating the UIViews purely in code, add then adding them to each of the section footers. This is working fine however the issue here is that I then cannot wire in my segue & segue identifier in IB. I am using the prepareForSegue method to send the correct data-model to the destination VC (depending on which segment footer button is pushed) so I require this. Is there an alternative here, can I trigger send my data-model in some other way?
Thanks, James

1 is possible.
Pull your customer view out of the nib as you would any other custom view Load View from Nib; then add it using:
- (UITableViewHeaderFooterView *)headerViewForSection:(NSInteger)section
edit Sorry, didn't mean to imply that #2 isn't also viable.
- (id)instantiateViewControllerWithIdentifier:(NSString *)identifier
// like this:
UIViewController * vc = [[self storyboard] instantiateViewControllerWithIdentifier:#"TheNewView"]
[self.navigationController pushViewController:vc animated:YES];

Using option 2, Create your segue from the view controller instead of from a specific view or button. Give it a meaningful identifier, then in the action method for your button, call performSegueWithIdentifier:sender: on your view controller. You can pass in any object you like as the view controller, including the index path or an NSNumber holding the section identifier, so you can access this in prepareForSegue and use the appropriate parts of your data model.

Related

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.

Segue to a subclass of some view controller

I'm using a storyboard. Let's say I have a view controller that's named MYviewController.
In - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender; I would like to substitute the view controller that I'm segueing to, by one of its child, for example: MYviewControllerChild1 OR MYviewControllerChild2. The child that's segued to depends on the sender parameter.
These view controllers have the same scene (in the storyboard). Only their behaviour is slightly different.
I have a tableView that shows the user the settings of the application. When he clicks a cell, it segues to a viewController where he can modify the value of some setting. Some of theses are alphanumeric, others are numeric. Depending on which cell is clicked, I'd like the input viewController to format the value accordingly (if it's a decimal value I'll use a NSNumberFormatter for example).
Is that possible?
As mentioned in comments to your OP, I believe you should handle this kind of scenario in one viewcontroller.
However, if you insist on using separate controllers, maybe because you think the functionality will be expanded later down the line and therefore add more diversity, you need to handle this by creating multiple storyboard scenes - one for each child controller.
The destination view controller in prepareForSegue is imposed by the viewcontroller at the end of the segue in the storyboard. I don't think there is any way to override that.
As described, your problem isn't really a good candidate for a storyboard. If you use a storyboard you will have to create and sync multiple scenes. Several possible solutions::
Create multiple storyboard scenes and invoke them manually via performSegueWithIdentifier.
Use a nib file instead of a storyboard for this scene. You can use a single nib file since the view controller is created outside the storyboard with [[VCClass alloc] initWithNibFile: bundle: You can create the appropriate view controller class and pass the same nib file to all instances.
Use a single storyboard scene and view controller and pass in typing information in your prepareForSegue.

Component reuse within Storyboard

I am new to iOS development, with a couple of years of Android experience. I started directly with XCode 5 and the Storyboard paradigm. I like the visual approach to sketching out the flow of an app, but IMHO, it does not really force component reuse, or maybe I do not know how to do it.
I have an actual problem, which is the following: Instead of the typical master-detail approach, I have a situation, in which clicking on a TableView cell forces a push to another TableView, which looks the same and behaves the same way. There are two specific types of a TableViewCell that I want to reuse across the whole application, so I can't just duplicate the first TableViewController several times. I need changes in one type of TableViewCell to be affected everywhere, same for the look and behaviour of the Tableview. Sort of like reusing a component, you get the picture I hope.
I tried creating a custom TableView and TableViewCell in a separate xib file, connecting it to a custom controller class. Yet, when I want to reuse that controller class in the storyboard, I can't make a segue from the cell to the next one, because only view controllers are displayed, but no views inside.
Maybe, I am doing it all wrong. Perhaps, I should make a single controller, and force it to seque to itself if possible, no idea.
What would you do?
You can do programatic Segue from the didselected.....
#import "someVC.h"
Then when you want to Segue to the new VC
// Create a VC and remember to set the Storyboard ID of someVC (example someVCID)
someVC *newView = [self.storyboard instantiateViewControllerWithIdentifier:#"someVCID"];
// Can't remember how this works but you can change the Transition method
// newView.modalTransitionStyle = UIModalTransition;
// If you want to pass data, setup someArray in the someVC .h with #property (nonatomic, strong) NSArray *someArray;
newView.someArray = MyLocalArray;
// Animated or not
[self presentViewController:newView animated:NO completion:nil];
If what you're trying to do is performing a segue on the same UITableView you can check this answer by Rob
I'll report what it contains for completeness:
If you're using dynamic cell prototypes, you obviously can do a segue
from the table view cell to the controller without any problem.
When you make your segue, you end up with:
But let's imagine for a second that there's some reason that doesn't
work for you, e.g. you could not have a segue from the cell (for
example, you need to invoke segue from didSelectRowAtIndexPath, not
upon selecting the cell). In this case, you couldn't use that previous
technique.
There are a couple of options in this case:
As pointed out by Chris, if only supporting iOS 6 and above, use the above technique, but (a) make sure your
didSelectRowAtIndexPath uses self for the sender and then have
shouldPerformSegueWithIdentifier only allow the segue if the sender
== self (thus when the sender is the table view cell, it will be canceled);
Perhaps even easier, just don't define a segue at all and have your didSelectRowAtIndexPath manually
instantiateViewControllerWithIdentifier and then push/present
that view controller as appropriate; or
You can use the following, kludgy work-around: In short, add a button to your view controller (drag it down to the bar at the
bottom), where it won't show up on the view, but you can use its
segues. So first, drag the rounded button to the controller's bar at
the bottom of the scene:
Now you can make a segue from that button to your view controller:
And thus, you end up with the self-referential segue again:
You must give that segue an identifier, so you can invoke it
programmatically via performSegueWithIdentifier, but it works. Not
the most elegant of solutions, but I think it's better than having an
extra scene on your storyboard.
None of these are ideal, but you have lots of options.
well.. in iOs think about it differently, if i were you i would create multiple ViewController, even if they're almost the same, and create a custom cell class, and make this cell take a configuration block.
Now for each ViewController (( or TableViewController )), you reuse your same custom UITableViewCell and just pass it what's slightly different for each case, and moreover you can also create a BaseTableViewController that will have the general configuration, and in each ViewController pass the custom changes you need.
Think about it, when you look at your storyboard you'll be able to see all your workflow, and when something goes wrong you'll be able to debug, if you have are gonna use what you suggested, debugging will be a real pain i imagine.
Anyway, try it out, and ask more if you need further clarification.

Dynamically created buttons and storyboard segue

I'm stuck because of this problem in my code:
I am using a storyboard, and have my custom tableview that is able to swipe rows uncovering the "background" where I can add buttons etc.
Problem is that the number and presence at all is managed in runtime (each cell can have multiple buttons or none - I'm adding them to the background view). Now I want these buttons to segue and I just cannot figure out how to do it in my storyboard...
Anyone had similiar problem or I'm just thinking wrong?
Another way to do this is to go ahead and create the segue's in the storyboard. You can't connect them to the button (since it doesn't exist yet), but you can connect them to the view that the table is in. You give the segue an identifier (by clicking on the line that is the segue and setting the property). Then, it is a simple matter of calling:
[self.storyboard performseguewithidentifier:#"theIdentifier"];
you can't make segue connections outside of the storyboard:
Creating a segue programmatically
You can make custom segues in code, but connecting the segues up to objects can only be done by drawing lines on the Storyboard.
But you don't need to. Segues are only dressed-up transitions between viewControllers. They are a visual tool for replacing a small amount of code.
A push segue just replaces this code for example
UIViewController* myViewController = [UIViewController alloc] init;
[[self navigationController] pushViewController:myViewController
As you are making your buttons in code, you should manage your navigation in code.
First of all you need to set the StoryBoard ID. You can do this by selecting a particular view controller and going identity inspector on the right side. Under the custom class, there is "StoryBoard ID", you have to set name "Menu"
Secondly, you need to call this storyboard from the buttons or any other control.You can do this by using the following:
[self.storyboard instantiateViewControllerWithIdentifier:#"Menu"];
This way you can give StoryBoard IDs to different controllers in your StoryBoard and call them from whatever control you want.
Hope this helps

Subview management within master/detail view in iOS (with ARC)

I have a master-detail controller for my app. The master controller is a UITabBarController and each tab is a UITableViewController that contains different types of data.
I plan on having a main header / image on the main detail view but then need to add different subviews to the main detail view to detail specific information depending on which tab I am using.
I am currently adding the relevant subview in my
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Function like so:
UIViewController *subview = [[UIViewController alloc] initWithNibName:#"ItemNotFoundViewController" bundle:nil];
subview.view.frame = CGRectMake(20, 160, subview.view.frame.size.width, subview.view.frame.size.height);
[self.detailViewController.view addSubview:subview.view];
However, I believe that this is a poor way of doing things - every time someone clicks on a table cell another subview will be thrown on top of the stack of previously added subviews, creating memory issues.
What I am wondering is, does ARC take care of this for me? Is my approach passable? and even if it is passable, is there a better way of doing this?
First of all, no. ARC does not take care of this for you. It's not it's purpose to do that and even if it was, how could it know, that you don't want the previously added subviews anymore?
You have to remove those subviews yourself and then ARC will take care of deallocating them (if there are no other references to them).
Anyway that's not the way you're supposed to use a UISplitViewController (the master-detail view controller). As you noticed the split view controller handles two other view controllers. The master- and the detailViewController. In most cases the master view controller isn't changing while the app runs (it's content changes, but usually that's handled by a container view controller like UINavigationController which is assigned as the masterViewController), but the detail view controller does.
Instead of adding subviews to your existing detailViewController you should replace it by a new one. So you should create separate XIBs (what you've apparently done already) for all the view controllers that you want to present in the detail-section. And modify your code to
self.detailViewController = newDetailViewController; //newDetailViewController would be the vc you called subview in your code
instead of
[self.detailViewController.view addSubview:subview.view];
Edit: Notice that this assumes that your detailViewController property does 'the right things' when you set it's value. By default the UISplitViewController only has a property called viewControllers which is an NSArray in which the first object is the masterVC and the second is the detailVC.
Take a look at MultipleDetailViews for an example of how to manage that.
Since you want to have a header view in all your detail view controllers you have various choice of achieving that (which may or may not be applicable in your case, depending on your design):
add the header view to every details vc's XIB
instead of creating many XIBs for all detailVCs, create a new custom UIViewController subclass that modifies it's content based on some parameters you give it, i.e. which tableViewCell was tapped by the user
create a custom container view controller that manages two child view controllers, one for the headline and one for the content above it.
For more information about UISplitViewController and custom container view controller, please refer to:
View Controller Basics
Creating Custom Container View Controllers
No, ARC will not take of this for you, because detailViewController.view will keep a reference to its subviews. It's hard to say what approach is best without knowing more about what you're doing with these views. It would probably be better to just present the new view controller -- it will be deallocated after it's dismissed if you don't have a property pointing to it.

Resources