Multiple View Controllers. Is there a maximum? - iphone

I am putting an iPad application together that allows a user to work their way through a virtual tour. They are able to move forward through screens on which some will have buttons to other material such as a video or more info.
If Keynote supported Hyperlinks then it would be well suited but as it doesn't I am trying to recreate the tour within Xcode.
I am a newbie but have spent time researching and have code to display the 'slides' and the capability to move forward and back through them. The slides are no more that an image view with a full screen graphic and buttons for the various options, some slides are simple and have nothing other than back and forward but others will have additional links
However doing it in this simplistic way means I am ending up with a huge number of view controllers and XIB files, currently at 75 which I know must be more than any app should have. However it does work although on occasions when running it on the device and not in the simulator it will bomb out.
My questions are is there a limit to the number of view controllers in one app and will having a large number cause the instability? I'm aware of other ways to handle the views such as having them in arrays and pushing them out a single view controller but this won't give me the flexibility to tailor slides for different content.
I'd welcome any help or advice and I hope have gone about posting this question in the right way (its my first)
Many Thanks
Kieron
The code I am using to manipulate the view is
-(IBAction)goBack {
[self dismissModalViewControllerAnimated:NO];
}
-(IBAction)goForward {
Slide5ViewController *screen = [[Slide5ViewController alloc] initWithNibName:nil bundle:nil];
screen.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentModalViewController:screen animated:YES];
[screen release];
}

Kieron,
Why not have one "slide" view controller and a different image only? Use some sort of data structure to keep information about the buttons, images, and pathways for each slide, and then just keep re-using the same view controller for each slide?
The view controller can then dynamically load each image as it transitions between the currently visible view and the next instantiation of itself... It should be possible using only 1 view controller.
If you're comfortable with using Interface Builder, keep using the XIB files to lay everything out. However, instead of setting each "File's Owner" to a different view controller, set them all to the same one. Then, inside your IBAction methods (when the user pressed a button), use some logic to say "I am on this view right now, and the user pressed this button, so which one should I go to next?"
Then, call a method like loadNewSlide: that might look like this:
- (void) loadNewSlide:(NSInteger)slideNumber
{
// Make a string with the new XIB name
NSString* xibName = [NSString stringWithFormat:#"slide-%d",slideNumber];
// Create the next slide view controller (it doesn't matter if you create a slide view
// controller from within another slide view controller, remember, they are all just
// objects)
SlideViewController *newSlideViewController = [[SlideViewController alloc] initWithNibName:xibName bundle:nil];
// Change the view
UIWindow *theWindow = [self.view superview];
[self.view removeFromSuperview];
[theWindow addSubview:newSlideViewController.view];
// Release, the view stack now should be retaining the view controller instead
[newSlideViewController release];
}
This will work MUCH better than running "modally" with 75 view controllers (as you had previously suggested) because this will only keep 1 slide in memory at a time - whatever you are currently looking at - and then will load the next slide just in time to move to it.

Fist of all, what error is in the log?
Did you properly implemented viewDidUnload method of view controllers? View controllers should be able to unload loaded xib. Also, release data in didReceiveMemoryWarning.
Second, it could be better to use UINavigationController to handle view controllers stack instead of modal view controllers stack. You can hide navigation bar or customize it.

Related

Using the same ViewController h and m files for 2 View controllers in Story Board

So I pretty much built my first app(single view) but i've now decided I should add a little "about/info" button and just give a tiny amount of information on how to use the app and a website to go to.
I wasn't sure about the best way to go about this but storyboards seemed really convenient. A user here answered my question about adding a storyboard to my existing project which seems to work.
Now one question is can I use my current viewcontroller h and m files for the second view (the about screen). I suppose it would technically work if I set the Viewcontroller to the same one as my primary app view.
the only thing this second view is going to have is text and a button to go back. Is it OK to set the connections in the storyboard and just let them use the same Viewcontroller files or is this a big no-no?
Thanks
It is recommended you use a different view controller for each view. In case of a static view controller in which the user doesn't interact with the view except maybe for navigation (which can be handled in the storyboard in many cases), I would just leave that view controller as a generic UIViewController, not a subclass.
Yes you can use the same view controller to control more than one view, however, from what I understand, that doesn't seem like good practice in your case
For instance, if you had similar views with almost identical outlets (say the views have the same UI widgets such as buttons, titles but their layouts vary significantly) you co[uld create a separate view for each different layout and use a single view controller. But from what I understand, in your case, those two views will have different outlets (buttons, labels, etc.)
For this reason, I'd suggest creating a new view controller. Then when you want to show this second view, you will have to present it from your active view controller. I'd highly recommend you read tutorials on view controllers in Apple developer resources. But very quickly, I'd suggest the following
UIViewController *vc2 = [[UIViewController alloc] initWithNibName:#"View2" bundle:[NSBundle mainBundle]]
[self presentViewController:vc2 animated:YES completion:nil];
And to go back to your main view, you'll have to dismiss this second view controller
[self dismissViewControllerAnimated:YES completion:nil];
Of course, they don't have to be animated, you can set them to NO.

iPhone Structure ViewController

I am designing an iPhone application with a home page. This page has multiple buttons (6) that go to different things.
2 buttons are a simple view that just have some information and go back to the home screen. The next button opens up an email and I believe that will just be one view, so not a whole lot different than the other two.
Here is where it gets complicated. One button will take a picture, and another will select one from the library. Once that is done it will edit it and create an object that I will create. That object will be stored in an array, which will be opened by the last button one the home page and a UITableViewController will control that.
My first question is should I use a navigation based view controller or just a view controller that I can create myself? Or should I use something that I don't even know about?
Please Help!!! And if you help a sincere thank you!
EDIT:
Well i tried it my own way first and the only issue i'm having is this code
- (void) displayView:(int)intNewView {
NSLog(#"%i", intNewView);
[home.view removeFromSuperview];
Instructions *i = [[Instructions alloc]init];
instructions = i;
[self.view insertSubview:instructions.view atIndex:0];
}
It is in my SwitchClass, which controls the Main Window's view. I know it is working there because when it first runs the switch class directs it to the home screen. I know the method is being called because the console is displaying the NSLog thing, but it just won't switch.
Aside from the fact that you have 6 buttons, I would try and use a UITabBarController for what you are trying to do; it would seem more natural to me (but you should find a way to reduce you 6 button to 5, otherwise they will not be displayed all at once).
Otherwise, a UINavigationController seems fine to me. For each button you push a new controller to deal with that button functionality, then you pop back. It should work easily.
EDIT:
have you tried with?
[self.view addSubview:instructions.view];
Your first question Yes you should use navigation based controller ... so when you press any button will open the other view controller with animation.. also Navigation Based Controller keep track of the parent controller if you have any created objects will be retained in the parent view controller that is the root of the Navigation.
here is the steps that you should use.
1-Create Navigation controller in the main application delegate and make it's root is the view controller.
2-when you push the view controller that have 6 buttons .
3- you can check this link for get photo album also if you have changed the source type to camera then you can get the image...
Photo Libaray
4- once you get the image you can add it to NSMutableArray that exist on the NavigationViewController root in your case will be the view which have the 6 buttons.
5-sice every time you want to view the array which contain the photos you will initialize the data source of the uitableviewcontroller with the array that you save photos on.
Thanks
I think the problem is coming from one of two places:
As I understand it, these are all different View Controllers, correct? And they have their own xib files? If that is true, then calling:
Instructions *i = [[Instructions alloc]init];
is insufficient. You need to use
Instructions *i = [[Instructions alloc] initWithNibNamed:#"Instructions"];
in order to include that view that you have already constructed in the interface builder.
The other thing I see potentially going wrong is that you are inserting all the views at the same index. Think of the index as a layer in photoshop. If you want the new view to be visible overtop of the last one, then it needs to be a higher index. This is handled automatically if you use addSubview: instead of insertSubview: atIndex:

how to unload a uiview

I am currently using this if statment to check if a uiview is loaded, this if statment works perfectly..
if (!myviewName.isViewLoaded) {
//not loaded so load my view
}
else (myviewName.isViewLoaded){
//is loaded so remove my view (unload)
}
However when I try to remove the view I dont think I am doing it correctly because I can never enter the first part of that if statement after the first time the view is loaded...
this is the code inside else (myviewName.isViewLoaded){
[myviewName removeFromParentViewController];
[animatedActionView removeFromSuperview];
the reason I use removeFromParentViewController is because I have added myviewName as a subview of animatedActionView, like so
[animatedActionView addSubview:b1VC.view];
[navigationController.view insertSubview:animatedActionView belowSubview:tabbarView];
the animatedActionView is being added as a subview to my navigationcontroller and I am placing it behind my tabbarview which is also a subview on my navigationcontroller..
hopefully this all makes sense..
Just to repeat my question, how do i remove a view so that it will access if (!myviewName.isViewLoaded) { properly.
anyhelp would be appreciated.
UPDATE:
As per reply I have been asked to explaine what I am trying to do in more detail which I will do here.
So, my original project has a NavController controlling all of the views I need for the first part of my project (querying the db) the second part of my project is displaying a ton or data.
So I am prototyping my final view in a new project to iron out all the problems I am likely to have, and also hopefully to do it in a way that will not get rejected by apple.
So when I reach the final view of my navController I am loading another navController inside of it. (will this get me rejected?)
this (sub)navController which I will refer to as otherNav will control the final view, it will load several different detailViewController with a special sliding transition animation which the user will be able to slide left and right between detailedViews.
I have also added a tabBar (in its own viewcontroller) as a subview to othernav, when the user transitions between detail views I plan to change the tabBar icons depending on the view, so when the user slide from one detail view to another then the previous icons will fade out and the new icons will fade in.
finally I have several other viewcontrollers which i call actionViews (this is what my question was about) which are loaded/inserted as subviews onto the otherNav but placed behind the tabBar and slide up and down when the tabbar button is selected and deselected.
here is a graphical representation of all of the views and how they sit on the screen.
You need to take care of myViewName's view:
[myViewName.view removeFromSuperview];
myViewName.view = nil;

UIView should have multiple UITableViews as subview

Hi I have placed three button similar to UISegmentcontrol. But its not, its just image buttons. Here I need to have a class called MainView(UIView) and child views like Breakfast, Lunch and Dinners(UITableView for all child view). By default MainView should load the breakfast class if i click the dinner button it should take me to the dinner class. I am able to work with single tableview but I dont know how to load other classes on clicking the button from the parent class.
The child views should appear for the full screen except the navigation items. Can you please provide me you support? Thanks
Switching between multiple different views using a UISegmentedControl, similar to iCal or the AppStore application.
Follow this link: HERE
The solution in this link is hands down the best solution I've found about the issue so far. With a little bit of adjustment it also worked fine with a tabBar at the bottom.
You want to display a new view controller on your navigation controller.
// .h file
- (IBAction)dinnerButtonPressed;
// .m file
- (IBAction)dinnerButtonPressed {
DinnerViewController *controller = [[[DinnerViewController alloc] init] autorelease];
[self.navigationController pushViewController:controller animated:YES];
}
And connect your button to the dinnerButtonPressed action.
The method creates a new DinnerViewController and displays it onto your navigation controller. You can then configure the layout of the dinner view controller in it's own xib (for example, you could add a table view ...)
From your comments to deanWombourne, I understand what you want to do. To accomplish that you have to modify the datasource that your current tableView is linked to, and then reload the tableView with new datasource.
But if I were you, I would go with deanWombourne recommendation and put each of those breakfast, lunch and dinner in separate views and push them into the stack, or I would go with UITabBar and put a tableView in each.

a question about rotation when multiple views are involved

I'm a relative newcomer to cocoa & programming for the ipad.
I've built an app that has a split view controller. In the detail view is a toolbar with a button on it. When the button is pressed, the split view controller is removed from the superview, and another view is put in its place. A toolbar button on this new view removes the view and puts the split view back. Works great... except when the ipad is rotated while the second view is visible. When the user returns to the split view, it's displayed as it was before the rotation.
The split view and all the sub views are set to autoresize=yes, and return yes when they receive the autorotatetointerfaceorientation message.
I'm guessing I need to tell the split view and its sub views to resize themselves when I add it as a subview to the window.
Thanks
Chris
Please see my question concerning this matter here:
Best way to switch between UISplitViewController and other view controllers?
If you use UISplitViewController as Apple intend you to, it's quite limited.
I ended up using a strategy exactly as you mention -- i.e. remove the UISplitViewController's view from UIWindow, and replace with another, and then later switch back. I found out that the orientation change WAS handled, even if I rotated while view B was presented (B being the non-split view), then switch back to A (the split view). However, I had to do a bit of fiddling with the frame size of the uisplitview to make it work. Will update with more info later when I find it.
There's also the option of writing your own split view controller, or using someone else's reimplementation, such as this one:
http://mattgemmell.com/2010/07/31/mgsplitviewcontroller-for-ipad
UPDATE
The fiddling I did with the frame size of UISplitView can be seen in the following method in my AppDelegate. These methods are for presenting the split view controller by replacing another top level view controller under UIWindow:
- (void)removeAllWindowSubviews {
for (UIView *childView in window.subviews) {
[childView removeFromSuperview];
}
}
- (void)presentSplitView:(UISplitViewController *)vc {
[self removeAllWindowSubviews];
UIView *viewForSplitVC = vc.view;
// fix for deficiency in adding a split view controller's view in landscape mode
// and it still having a frame for portrait mode.
// 2010-10-15 added -20.0f to fix problem with toolbar in LHS VC being 20 pix too low.
viewForSplitVC.frame = CGRectMake(viewForSplitVC.frame.origin.x, viewForSplitVC.frame.origin.y,
navigationController.view.bounds.size.width, navigationController.view.bounds.size.height - 20.0f);
[window addSubview:viewForSplitVC];
}
// for removing the split view and restoring the other main VC
- (void)restoreMenu {
if (isIPad()) {
[self removeAllWindowSubviews];
[window addSubview:navigationController.view];
}
}
As I said, it's a hack, but the correcting of the frame gave me the ability to present the split VC without its frame being sometimes incorrect. And as I noted earlier, by doing this stuff, we're going outside what Apple want us to do, hence the hackery involved.
Ok, I have an idea for what might work: Don't remove the UISplitViewController's view from the view hierarchy. Instead, either put a view on top of it, set the alpha property of its view to 0 or set the hidden property of its view to YES.