I'm trying to put together an iPad app using UISplitViewController and storyboards. The master view starts with a navigation controller linked to a table view of 6 menu options. Each cell in the table pushes a different table view controller onto the navigation stack. This is working fine for the master view. Each master view has a table list which when clicked needs to display a different view controller in the detail pane. I've currently done this with a segue set to 'Replace' and 'Detail Split' which works the first time a row is clicked, but as soon as you click another row in the master view, or rotate the device then the app crashes with EXC_BAD_ACCESS.
I'm fairly sure my problems are to do with how the delegate is setup for the UISplitViewController. I'm confused as to how this should be used when I have multiple master VCs and multiple detail VCs. Where should the delegate code be placed - master or detail? Do I have to implement the UISplitViewControllerDelegate protocol events in every view controller?
Any help appreciated.
If the split view controller delegate was the detail view controller that had been replaced, this is the cause of the crash. The replaced detail view controller is being dealloc'd and so the split view controller delegate is no longer a reference to a valid object.
You can update the delegate in prepareForSegue:sender:. For example:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([[segue identifier] isEqualToString:#"MySegue"]) {
UIViewController *destinationViewController = [segue destinationViewController];
if ([destinationViewController conformsToProtocol:#protocol(UISplitViewControllerDelegate)]) {
self.splitViewController.delegate = destinationViewController;
}
else {
self.splitViewController.delegate = nil;
}
}
}
Which view controllers you use for delegates is dependent on your view controller hierarchy. In the simplest case, any view controllers that are assigned to splitVC detail will probably need to be delegates. You may want to base them all on a common super class that handles the shared split view controller delegate logic.
Related
Is it possible to have one view controller save data or control two views?
Say like a 2 page questionnaire. Instead of have a view controller for each page can one view controller save data from both?
You can, yes, but only one view can be considered the view controller's actual view (the property)
This is important because sublassed view controller methods like
-(void)viewDidLoad
-(void)viewWillAppear
etc
will only call for the actual view of the view controller.
Simple answer YES you can have one view controller and control multiple views on that view controller.
I realized that I have to still treat the second page differently even though it uses the same view controller.
I solved my problem by
-(void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
Test *vc = [segue destinationViewController];
vc.testInt = 2;
}
I have created a signup form in the parent controller and integrated a navigation view controller. Then I connected both the controllers through push segue.
I am stuck with how to transfer data from UITextField in the parent view controller to the navigation controller using the click event of the button placed on the signup form.
Anybody please help me.
Thanks
When a segue is triggered, before the visual transition occurs, the storyboard runtime invokes prepareForSegue:sender: method of the current view controller.
By implementing this method, you can pass any needed data to the view controller that is about to be displayed.
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"StoryboardIDOfViewControllerThatWillBeShown"])
{
YourViewController *destinationViewController = segue.destinationViewController;
destinationViewController.dataToPass = _yourTextField.text;
}
}
The best practice is to give each segue in your storyboard an unique identifier. This identifier is a string that your application uses to distinguish one segue from another.
Here is the full description of Passing Data Between View Controllers.
I'm brand new when it comes to app development so this might be a stupid question.
So i have made a UI table. It is customizable, as in users can insert or delete rows. I want to allow users to click on a table cell and it'll direct them to another view controller. All the view controllers will look the same for each cell (sorta like a template). Any idea how to implement this using storyboard?
Appreciate it!
You do not need an array of view controllers. All you need is one view controller, which gets instantiated when the user clicks the cell to navigate to it, and gets deallocated as soon as the user closes the screen to go back to your main view controller.
All you need to implement this in your storyboard is adding a push segue from a cell or a button in your main view controller to your "detail" view controller. When the segue gets triggerred, your code gets a chance to configure the newly created "detail" view controller in the prepareForSegue:sender: method, before the controller's view appears on the screen. This is the place where you customize the data that shows up in the detail view (presumably, depending on the particular row in the table that has triggered the segue).
Here is a link to a good tutorial explaining how to build a master-detail application with Xcode and storyboards.
In storyboard you create a viewcontroller that will display the data after a cell has been selected, you will only need one and not an array. Link it from the tableviewcontroller to the new viewcontroller. Click the segue in Xcode and in the inspector give it a unique identifier.
tableView:didSelectRowAtIndexPath: will get called when you select a cell, here you can perform the segue:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
self.selectedObject = ... // store the object that was selected
[self performSegueWithIdentifier:#"mySegue" sender:self];
}
In your tableviewcontroller you make sure you implement prepareForSegue:sender:. Here you can hand over the correct model object to populate your destination viewcontroller with data.
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([[segue identifier] isEqualToString:#"mySegue"])
{
MyDetailViewCotroller *controller = [segue destinationViewController];
controller.dataObject = self.selectedObject;
}
}
Check out this example code from Apple (does not used Storyboard though): http://developer.apple.com/library/ios/#samplecode/SimpleDrillDown/Introduction/Intro.html#//apple_ref/doc/uid/DTS40007416
I have two scenes. A regular, full-screen iPad view and another popover view. Tapping a button loads the popover view with no problems. In the popover view I have a button that will perform some action and is also linked to a storyboard modal transition.
The idea is that pressing the button from the popover view will save the user's selection state and send that data to the main view. I have no issues with the data saving, that works just fine.
The issue I am having is that when I press the button from the popover view, the main view's viewDidLoad method actually completes before the popover view's IBAction method does. So the main view gets the data, but since the view already loaded it is not able to update the label in time.
I tried creating multiple popover view scenes and added multiple buttons to the main view that will link to these new scenes. The weird part is that some of them work just fine. Some of them will perform the IBAction method and then it transitions back to the main view via a modal transition. There seems to be no rhyme or reason why one loads before the other.
I suppose a possible solution would be to perform the transition manually within the IBAction method of the popover view. I am definitely new to this so there may be something fundamental about transitions that I am missing.
In the view controller of view on which the button is present... When segue is going to be performed. You can pass data in
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
// Make sure your segue name in storyboard is the same as this line
if ([[segue identifier] isEqualToString:#"YOUR_SEGUE_NAME_HERE"])
{
// Get reference to the destination view controller
YourViewController *vc = [segue destinationViewController];
// Pass any objects to the view controller here, like...
[vc setMyObjectHere:object];
}
}
This method is called before the view is loaded..
If you are calling a popover so the main screen should not call viewDidLoad method because the main view still on the back. It should be calling the viewWillAppear and the viewDidApper methods instead.
Can you check this? I think you should refresh the main screen after one of these two methods are called.
Give it a try and tell me the results.
I've got an iOS app that has a page view to show multiple items as pages. Each page contains a tab bar controller with 2 tabs so I can show the info for each page in 2 ways - as a table or as a graph. Here's a screenshot:
So the user chooses which item to look at (in this case bananas) by changing pages. But I can't figure out where or how I should inject which item they're looking at into the 2 view controllers within the tab controller. Here's a shot of my storyboard if that helps. I want to inject it when the table view controller or graph controller are created but I can't see where that's happening to get at that code - have I missed something?
Thanks.
Not sure if this will work the same in the storybaord environment, but there is UITabBarControllerDelegate that has a callback method named didSelectViewController. It will give you the viewcontroller that is being selected. Doc from Apple.
If my understanding is correct, you should subclass your tab bar controller and implement the
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
method.
In there you can access the destination view controller by the segue object's destinationViewController property.
Depending on the segue identifier you can customise your destination view controller:
if ([segue.identifier isEqualToString:#"SegueID"]) {
MyViewController *myViewController = (MyViewController *)segue.destinationViewController;
//customize view controller
}