Converting iPhone application into iPad, and then use splitview in iPad? - objective-c

I've made a diary application for iPhone and I want to make it universal (iPhone and iPad).
When the application Launches in iPad, I want it to use a split view controller.
I have two classes. The first one is "Rootviewcontroller" and the second one is "Detailview" Controller. In both classes, I use the navigation controller. In the iPhone, when the application launches, rootviewcontroller is visible. Using the navigation controller, the user can move to the detail View.
On the iPad, I want the root view controller to be on the left side of the split view controller, and the detail view on the right side.

If you check out the Apple Documentation, you just have to assign the two view controller when you initialize the UISplitViewController. Here's a link to the Apple Documentation - http://developer.apple.com/library/ios/#documentation/uikit/reference/UISplitViewController_class/Reference/Reference.html
Here's an example from an actual iOS application we have (changed some variable names to make it easy to understand). We basically determine if the device is an iPad or not, then build the master navigation controller.
detailNav is the a navigation controller created with the "detail view controller of our item"
masterNav is the navigation controller used with our iPhones. It starts the users on a tableView which allows them to select an item to move forward to a detail view.
We assign both of these to an array and initialize the split view controller.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPad) {
UINavigationController *detailNav = [[UINavigationController alloc] initWithRootViewController:detailVC];
NSArray *vcs = [NSArray arrayWithObjects:masterNav, detailNav, nil];
UISplitViewController *splitViewController = [[UISplitViewController alloc] init];
[splitViewController detailVC];
[splitViewController setViewControllers:vcs];
[[self window] setRootViewController:splitViewController];
} else {
[[self window] setRootViewController:masterNav];
}
This is most likely not the best code or best practice as me and my team are still fairly new to the iOS world, but I hope it helps. This code is running on a live app in production.

Here's apples docs on how to do it: http://developer.apple.com/library/ios/#DOCUMENTATION/iPhone/Conceptual/iPhoneOSProgrammingGuide/AdvancedAppTricks/AdvancedAppTricks.html
To implement the split view it is in the iPad view controller, if you want to change the side the split view is on you can subclass it and redraw it on the right. Hope this helps!

Related

UISplitViewController iOS8 PopToViewController programmatically

I'm using an UISplitViewController and Size Classes on my application.
I'm displaying Master & Detail controllers all the time on iPads (UISplitViewControllerDisplayModeAllVisible)
I set up my storyboards following this great SplitViewController tutorial
So I'm supporting iOS 7 and 8 on my app. Everything is working but for a small problem I'm experiencing on iPhones with iOS8: (this doesn't happen in the 6+ landscape of course)
I want to programmatically show the Master Controller from the Detail controller.
I'm able to do this with:
[self showViewController:[self parentController] sender:self]; //Parent Controller is Master Controller
But this causes the Master controller to be pushed in top of the Detail Controller causing the back button of the navigation bar to stop working.
If I use:
[[self navigationController] popToViewController:[self parentController] animated:YES]; // This works on iPhones with iOS7
The application crashes with: 'NSInternalInconsistencyException', reason: 'Failed to get popped view controller.' (I also tried popToRoot... nothing happens.)
Debugging the code I found that SplitViewController.viewControllers returns only a NavigationController with the Detail controller inside, so the Master is not inside nor root of the Navigation Controller.
But if I press the back button of the Navigation Bar it makes the pop animation simulating the Master was root.
I'm assuming this is all related to iOS8 and the fact that for iPhone 6+ you can have both Master and Detail visible on Landscape mode so the OS no longer keep both of them inside a NavigationController.
But my question is how can I programmatically pop to Master controller from the Detail then?
Currently I fixed this problem with the code below, but I would love to know if there is a better way to do this.
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
// iOS 8 and later only.
if (self.splitViewController) {
// If it's not an iPhone 6+ landscape.
if (self.traitCollection.horizontalSizeClass != UIUserInterfaceSizeClassRegular) {
UINavigationController *nav = self.splitViewController.viewControllers[0];
nav.viewControllers = [NSArray arrayWithObjects:self.parentController, self, nil];
[[self navigationController] popToViewController:[self parentController] animated:YES];
}
}
else {
[[self navigationController] popToViewController:[self parentController] animated:YES];
}
}

Setting up and using the UINavigationController class in Objective-C

I am trying to use the UINavigationController class in Objective-C, but I am having a difficult time understanding how it should work.
Basically, I have my app. I want to use the UINavigationController to show a hierarchy of data stored in an NSArray. I currently have this data being presented in UITableView. I want to make it so a user can click on a row of the table view and be taken to more specific data about the row they just clicked. I think a UINavigationController is perfect for this.
However, my understanding of MVC in the context of Objective-C is not that good and I am confused about how to do this. I want the UINavigationController to only show up in the left half of my iPad app and I would also like the ability to hide it at times. So how do I configure this?
This sounds like the correct usage for a navigation controller.
What you will need to do is create your navigation controller and populate the root view with your view controller containing the table view. In your didSelectRowAtIndexPath you would push the detail view onto the stack. All the navigation will be set up to go back for you.
Most likely in your AppDelegate:
ListViewController *theView = [[ListViewController alloc] initWithNibName:#"ListViewController" bundle:nil];
UINavigationController *navView = [[UINavigationController alloc] initWithRootViewController:theView];
[theView release];
[window addSubview:navView.view];
[window makeKeyAndVisible];

Obj-C, Navigation Controller with Tab Controller am I using them incorrectly?

When I first setup my app I had some issues getting a single navigation controller to work.
I have several screens behind each tab item. I think the problem I was getting was that view controllers would show within the wrong tabs, when switching between them. I'm not bothered about keeping the last view controller used open within each tab, in fact I hide the tab bar to stop this anway now.
So at the moment I have navigation controller files for each of my tabs. I have them assigned in IB, in the mainWindow.
And I use them like this...
CategorySelTableViewController *nextController =
[[[CategorySelTableViewController alloc] initWithNibName:
#"CategorySelTableView" bundle:nil] autorelease];
nextController.hidesBottomBarWhenPushed = YES;
MyAppDelegate *delegate = (MyAppDelegate *)[[UIApplication sharedApplication]
delegate];
[delegate.billsndepsNavController pushViewController:nextController animated:YES];
However, I have some leaks.
I can't release my delegate, it causes an error.
My colleuge suggests that I should just be using self.navigationcontroller.
But this is a big change for me, I'd like to know definetively if I'm doing this wrong before I make the changes ?
When a view controller is pushed into the stack, it has two ways to access the navigation controller:
Using self.navigationController.
Accessing the navigation controller ivar in the delegate:
[UIApplication sharedApplication].delegate.navigationController
Both are equivalent but the first one is shorter, so it tends to be used more. There is no benefit from switching from one to the other. The only reason to do the extra typing is when you are not in a pushed view controller, eg: a view controller used in an independent GUI component, or an object that is not a view controller.
The delegate shouldn't be released because it exists during the whole life of the application.

loading a UINavigation controller from a UIView

i am designing an app that has a login screen. it is a UIView with username/password and a button to submit. once the user authenticated successfully, i want to load a new xib file that holds a navigation controller and a navigation bar. below the bar i want to load a tableView and switch between other views as i move along with the programming of it.
what i did is create a new class that inherits from UINavigationController and assembled the xib file to include the navigation controller. i hooked it back up to file's owner and i'm loading the navigation controller modally like this:
myNavController* navVC = [[myNavController alloc] initWithNibName:#"navXibFile" bundle:nil];
[self presentModalViewController:navVC animated:YES];
[navVC release];
this works okay as the navigation controller shows up. however, it shows up with no title, even though i've set one up in IB. moreover, the tableView's delegates are hooked up via IB but i cannot even see empty lines. all i see is an empty navigation bar at the top and blank view (one piece) below it.
thank you for your help.
so i figured it out... first it's a design decision right? is the app being managed by a navigation controller? if so (which is my case), expect the main (first) view, that is a login page, all you need to do is to hide the navigation bar in your ViewdidLoad for the main view:
[self.navigationController setNavigationBarHidden:YES animated:YES];
once the user logs in and you push the next view like this:
MainTableViewController* mainTableVC = [[MainTableViewController alloc]
initWithNibName:#"MainTableViewController" bundle:nil];
[self.navigationController pushViewController:mainTableVC animated:YES];
[mainTableVC release];
and lastly, in the ViewDidLoad of the next view controller:
[self.navigationController setNavigationBarHidden:NO animated:YES];
in case your app needs a navigation controller for a specific section of the app but not all if it, you will need to use the VC to manage this, in a similar way the appDelegate manages the sample navigation based sample app.
i hope this helps anyone struggling with wrapping their minds around the design patterns implemented here.
cheers.

Developing a NavigationBar Based application including one Open GL View : How?

My question starts from a problem :
I started a project in Xcode : a Navigation Bar based one (with a TableView).
Then I added a few views, through IB or programmatically... which works perfectly fine.
Then, I decided to write my Own ViewClass, inherited from UIView, called OpenGlView (based on the view provided by Basic OpenGlES project in XCode), and its OpenGlViewController (inherited from UIViewController).
This works fine until I try to push the view Controller into my navBar: then I receive a "EXC__ BAD __ACCESS". I can't understand why it is ok whith any view but the one used for display OpenGL content...
And I actually have no idea how I can manage to develop a NavBar based App including a View displaying OpenGL contents... any idea?
(I also tried to add the OpenGlView as a subView of a basic UIView previously added to the NavigationBar, but I received the same error).
In the RootController :
OpenGlViewController *glvController;
if (glvController == nil)
{
glvController = [[OpenGlViewController alloc] initWithNibName:#"Gl View" bundle:nil];
glvController.title = #"GL View";
}
[self.navigationController pushViewController:glvController animated:YES];
in the OpenGlViewController :
- (void)loadView {
OpenGlView * view;
view = [[OpenGlView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
self.view = view;
[view release];
}
If it's localized to your OpenGL view, the crash may be the result of not properly initializing OpenGL items inside your view. See here for my recommendations on a potentially similar problem.