custom container view controller + storyboard? - objective-c

I want to implement my own container view controller.
Pls, imagine that this is my ipad
Kind of usual split view controller, but I want to extend it: width of view "a" should be resizable, when I tap view 'B' - view 'C' goes to visible area
For instance in my storyboard, I have 3 container views: AViewController (for A view), BViewController,CViewController and one combined view controller (initial view controller).
In combined view controller i will implement embed segues from container view and initialize relationship between container views via following code:
#property ... *aViewController,*bViewController,*cViewController;
- (void)prepareForSegue:(UIStoryboardSegue *)segue
sender:(id)sender
{
if ([segue.identifier isEqualToString:#"EmbedAViewController"])
{
self.aViewController =
segue.destinationViewController;
}
if ([segue.identifier isEqualToString:#"EmbedBViewController"])
{
self.bViewController=segue.destinationViewController
}
-(void)viewDidLoad
{
[super viewDidLoad];
self.aViewController.bViewController=self.bViewController;
}
Question1: Is it proper way implement my assignment using storyboards?
Question2: What kind of limitations does container view have? Is it a visual replacement of addChildViewController API? If no, where should I implement child-parent relationship? I should use in my combined view controller in prepareForSegue method
[self addChildViewController:aViewController];
[self.view addSubview:aViewController.view];
Question3: How to put container view outside of visible area at the beginning?
If I somewhere did a mistake or have a big misunderstanding of basic concepts, do not beat me. I did a lot of google-foo, I would really appreciate any help. Great thanks in advance!
Edit:
I want to set up relationship between all of them. "B" view's content depends on "A", and "C" view's content depends on "B".

I think you do have some misconceptions. If you want to implement container view controllers in a storyboard, you don't need to do anything in code. Start with one controller, the one you're calling combined view controller, and drag in 3 container views. Initially, you might want to size them so they are all full height, and make them all fit side by side in the main view. You can then change their sizes and positions using the size inspector, so that C's view starts at the right edge of combine controllers view, that way it will be off screen to start with. You will automatically get three view controllers connected to their respective container views with an embed segue. All three of these controllers will be instantiated at the same time as combined controller. You will need outlets in combined controller to each of its container views, so that you can resize them as necessary in code.

Related

Avoid using prepareForSegue in Objective-c?

In my initial view controller, I have the following code:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"showSearch"]) {
[segue.destinationViewController setInitialLocation:self.locationManager.location];
}
}
When a button is pressed in the initial vc, the segue labeled "showSearch" is activated and the second view controller is loaded with the data inside. The second view controller is a map, and the data are pins at certain locations, collected from the Parse database. My question is, is there anyway to avoid the initial view controller? In other words, I don't want to load up my app, then have to press a button to get to the map view. I want the map view to load first, with the pins already on the map.
You can change your initial view controller by going to storyboard, selecting the view controller you want to become the new initial view controller, going to the attributes inspector, and checking "is initial view controller."
In first view controller's viewDidLoad call the button method which is responsible for the segue to second view controller.
Solved the problem by adding this to the viewDidLoad.
[self performSegueWithIdentifier:#"showSearch" sender:self];
Not ideal, but it works. Although it works fine on my phone, it doesn't seem to work perfectly on the xcode simulator.
If you have a lot of database related code in an initial VC, but that VC isn't handling an UI, maybe you could change your program so that the database code was separated out into its own class. Then the map VC can be your initial VC and it can call your database class to get the data.
So, maybe you have a location manager class with a getInitialLocations method that the map VC can call to load itself with data. Just guessing based on your description.

Reuse UIViewController instances when using storyboard

I decided to give the use of storyboards a go in my current iPhone app. I am facing a bit of a problem. I really need to reuse my UIViewController instances.
What do I mean by that? Well, for example I have a table view controller. When I tap a cell, another view controller is loaded from the storyboard and pushed onto the navigation controller stack. This all works well, but it takes about half a second to a second each time this view controller is loaded. Before I was using story boards I simply solved this problem by caching the created instance so the second time you tap a cell the view controller can be immediately shown.
By caching the created instance I mean something like this:
if (!cachedInstance) {
cachedInstance = [MyViewController new];
}
[self.navigationController pushViewController:cachedInstance];
Does anyone know how to accomplish this using the storyboard? Thanks in advance.
If you are using segues, you will need to create custom segues in order to use a cached view controller like you did before. Otherwise, the typical "push" segue will create a new instance of the view controller for segue.destinationViewController. If you write a custom UIStoryboardSegue class and use custom segues you can override initWithIdentifier:source:destination: and put your cached view controller in for the destinationViewController, and then override perform to use the classic pushViewController call.
That is how you handle the segue if you are really intent on using them. I would just skip it though, unless you really want the fancy arrows to lay everything out on your storyboard. If you skip it you can just instantiate the view controllers into the cache and then push them on just like you did before.
If your question is more about locating a view controller inside a storyboard then you can use:
UIViewController *vc = [[UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil] instantiateViewControllerWithIdentifier:#"Some View Controller"];
Then you can save that to your cache and push it like you did in your example code.
Hope that helps.

Resize master and detail view controllers in a split view controller?

I'm working in Xcode 4.2 and am developing an app where I want the menu screen to use a Split View. Really, all I need the Split View Controller for is to split some of the menu options into a left pane and right pane. I want to be able to set custom sizes for the master and detail view controllers, but nothing seems to be working for me. I've tried updating the frame sizes for each view controller with code like:
[self.view setFrame:CGRectMake(0, 0, 768, 502)];
in the viewDidLoad functions, but that doesn't seem to affect anything.
Is there a way to set custom sizes for the master and detail view controllers of a split view controller without instantiating the view controllers in say the AppDelegate.m file? I want to be able to edit each of the view controllers in the storyboard as they are menu screens with a lot of buttons and such.
Edit:
In iOS 8+, the relative widths can be changed by specifying the minimum/maximumPrimaryColumnWidth properties or the preferredPrimaryColumnFraction.
The below answer is still true for iOS < 8:
You can't change the sizes for a split view controller.
See here: http://developer.apple.com/library/ios/#featuredarticles/ViewControllerPGforiPhoneOS/Introduction/Introduction.html
"The UISplitViewController class is a container view controller that manages two panes of information. The first pane has a fixed width of 320 points and a height that matches the visible window height. The second pane fills the remaining space."
Use MGSplitViewController. It offers similar API to UIViewController, but offering additional features, such as split position, which is what you need.
- (CGFloat)splitView:(NSSplitView *)splitView constrainMinCoordinate:(CGFloat)proposedMinimumPosition ofSubviewAt:(NSInteger)dividerIndex;
{
return proposedMinimumPosition + 238;
}
- (CGFloat)splitView:(NSSplitView *)splitView constrainMaxCoordinate:(CGFloat)proposedMaximumPosition ofSubviewAt:(NSInteger)dividerIndex;
{
return proposedMaximumPosition - 200;
}
before the above delegate method add [splitView addDelegate:self];

Storyboard relationship in iOS

I'm attempting to use the new Storyboard feature, however I am confused about Storyboard Relationships? How are they different to IBOutlets?
Also how can I add my own relationship, to my own UIViewController subclass?
I have tried looking in the documentation but can't find much about them.
The way I understand it is: relationships are iOS's way of representing a 'parent-child' relationship and while that does seem quite recursive, an example of parent-child relationship is a UIViewController Container containing a UIViewController.
That's the theory anyway -- it's better understood using the UINavigationController. It is called a 'container' because it contains as many regular UIViewControllers in a 'stack' metaphor so you can do your normal UITableView drill downs and pop offs.
The key point is that the segue between UINavigationController and the first UIViewController in your stack, there is a 'relationship' while the segue between all the rest of the UIViewControllers is just a regular push segue.
The same thing is evident in the UISplitViewController -- it needs two view controllers (sometimes called content view controllers) from launch and these are connected up between the parent UISplitViewController (the container) and two regular (content) view controllers
(thus relationships are not like IBOutlets, but more like segues -- they are even in the 'segues' category of the standard view controller containers)
Now - we aren't allowed to subclass the standard view controller containers, but we are allowed to create custom view controller containers, but I can't for the life of me define a relationship in my custom view controller container!!!!!!!!!!!
so: "can I use them in my own controllers?" the answer is yet unknown (to me at least, and the documentation is thin at best)
Create a subclass of the UIStoryboardSegue like this:
#implementation JTARelationshipSegue
- (void)perform
{
return;
}
#end
Make a custom segue between your two objects and set the class as JTARelationshipSegue. In your view controller make the view controller perform the segue like this:
- (void)viewDidLoad
{
...
[self performSegueWithIdentifier:#"addChild" sender:self];
}
You need to have set the segues identifier in interface builder to addChild.
Impement prepareForSegue:sender so that it adds the segues destination view controller as a child of the current view controller, like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
UIViewController *destination = [segue destinationViewController];
[self addChildViewController:destination];
...
}
You will need to have a different segue identifier for each child that you want to create (or another way of identifying the specific view controller.
This will make your storyboard file look prettier, and more readable, however you may do better to just load your other view controllers and add them as children in your view did load method:
- (void)viewDidLoad
{
[self addChildViewController:
[[self storyboard]
initiateViewControllerWithIdentifier:#"myIdent"]];
...
}
I wrote a few tutorials on how to use storyboards over on my site...
Part 1 of tutorial
Part 2 of tutorial
Perhaps that will help a little bit? In essence, the Segue relationships provides an identifier for the link between two items on your storyboard. You can use these identifiers to manage how things work.

Objective-C: How to send signal from view to view controller to change views?

I have a view controller that controls the switching between views. I would like one of the views to signal the view controller to switch to another view (and can't figure out how I can do this.)
To be more clear (hopefully): My view controller inserts a subview. That subview has a UITableView. I'd like, when you select a row in the UITableView, to remove the current subview and then switch to a different sub-view. Of course, I'd prefer the view controller to continue to keep track of which subview is loaded.
Does this make sense? (I'm still pretty green with Objective-C.)
Is there a way to send the view controller a message from the sub-view (that the view controller created)? Is there another way to accomplish this?
Thanks a bunch for the help... and I'd be happy to clarify if needed.
You might look into setting up a UINavigationController. Use the 2 UIViewControllers to control the individual views, and use the Navigation Controller to switch between the 2 views. From the UITableView, you can simply implement the method -
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
Use this method to alloc the new view controller that you want to display
Then call the Navigation controller to push the new view controller onto the stack -
[self.navigationController pushViewController:controllerName animated:YES]
Finally, release the view controller that has disappeared.
This way the navigation controller keeps track of who is loaded, and can implement convenience functions like animating the transition. Also make sure to lookup the UITableViewController subclass - it is a subclass of UIViewController, but it provides some convenience functions for dealing with tables, like knowing when the user selects a particular row, and allows for the standard edit functions of most iOS apps.