iPhone Structure ViewController - iphone

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:

Related

Right way to switch between UIViews in ios programming

Hy everybody
I am a newbie ios programmer and I'm facing many doubts when I must switch the pages of my app.
With the term "page" I mean a UIView that fills the whole screen with some widgets (buttons, textboxes. tables..)
As far as I have understood what I've read I should use an UIViewController to manage each of these pages
since each page should be a screen’s worth of content.
My App starts with a ViewScroller with many buttons and when the user clicks one of these it opens a new page.
The first page is the UIView connected to the RootController Of the Window.
So far to open the new pages I add a child controller to the RootController and it's view as a child of the view of the RootController:
RicLocaliController = [[RicercaLocaliViewController alloc] initWithNibName:#"RicercaLocaliViewController" bundle:nil];
[self addChildViewController:RicLocaliController];
[RicLocaliController didMoveToParentViewController:self];
[self.view addSubview:RicLocaliController.view];
RicLocaliController.view.frame = self.view.bounds;
When the user clicks the "Back" Button I remove the child controller and the child view.
Going down this road I would get a dynamic tree of Controllers with their Views.
So far I have not encountered problems and my app can go up to a third level in the tree and come back. Each page behaves correctly when orientation changes.
But I'm afraid that adding, for each subpage, a child controller and a child view could be not the right thing to do.
I'm afraid that if I nest a lot of pages when the orientation changes the app could respond slowly since also the superviews will do something to manage this event.
So what I wonder is if what I am doing is completely senseless, if I should use Navigation controllers or some other way to manage my page changes.
Unfortunately my boss is not giving me enough time to study well the subject and so I would like an advice to follow the best solution possibly using the most standard and less complex component offered by the framework instead of the newest features.
I read a lot of web pages on the subject but it seems to me that there are many ways to manage the navigation beetwen pages and this makes me confused.
I apologize for my bad english but i'm tired and English it's not my first language.
You HAVE to do some studying. You will spend more time clearing up all your problems later otherwise... but, here are some tips.
Using nested ViewControllers leads to all kinds of trouble so if you are short of time, skip that.
Think of each "Page" as one ViewController. A ViewController has a property called View but that is actually just the top view of a whole hierarchy of views. A view is the base class for any visual object, like labels, buttons etc. All views can have subviews, so you can add an image under a label etc. and do really wierd stuff if you want to. I am just saying this to free your mind about how you can use views.
Now, ViewControllers are supposed to hold to code to ONE view hierarchy. That view hierarchy is for that View Controller only.
When the user wants to navigate to another page, you have a few alternatives:
NavigationViewController - that should be used when the user wants to delve down into data, like opening a detailed view of an item in a list etc. The NavigationViewController gives you help with back buttons, proper animation etc. You "pop" a viewcontroller to go back one level. If the user click the back-button, this is automatic.
TabBarViewController - use that if you want a tab bar at the bottom of the screen. Each tab is connected to a ViewController, that has it's own view hierarchy.
PushModal - If you are in a ViewController and just needs to get some data from the user, which is not part of the normal navigation of the app, you can push a new ViewController modally. This is the way you interact with iOS built in ViewControllers. This is also a good way to get a value back from the view controller.
There you have it. Go learn more. :)
It sounds like, for what you are using, you should be using a navigation controller. This will automatically handle pushing views onto the stack and then popping them off again later. This will also automatically create a back button (it is customizable) in the navigation bar.
If you are using iOS 5 or 6, I highly recommend trying out "storyboards" in Interface Builder. Storyboards allow you to graphically represent transitions (called "segues") between different views.
On top of being easier to design and implement, another advantage is that, if in the future you want to change the design of your application, you don't have to trawl through all your code and manually update each view connection.

Pass a UIViewController/UIView between the views of UITabBar tabs

Ultimately, I'd like to know how to store a UIView (globally, if necessary) from one view controller, so that it can be referenced, and called back up to the top, from within another view controller?
I've built an app that has a Home tab and a Guide tab as the two main tabs, but the Guide tab's functionality is a bit unique in that it's a dynamic tab, which will ideally show different content depending on what "guide" has been chosen from the Home tab. Thus, on the Home tab, there are several UIButtons that are meant to load a given guide. Each guide is simply a collection of images that the user can interact with. No problem there.
Now, on the Home tab, when a user selects the guide they want to view, I wanted to transition between the Home tab and the Guide tab with a CurlDown animated transition. This is the only place I'll have a UIView transition animation—meaning normal tab switching by the user will be the standard instant transition without effects.
Here's how I have implemented the Home-to-Guide transition when a user selects a guide from the Home tab. This is done in the HomeViewController, as an IBAction assigned to all the guide-loading UIButtons, each of which has a unique tag that tells the GuideViewController which guide to load:
- (IBAction)loadGuide:(id)sender
{
UIButton *button = (UIButton*) sender;
GuideViewController *guideController = [[GuideViewController alloc] initWithNibName:#"GuideViewController" bundle:nil];
self.guideViewController = guideController;
[self.guideViewController activateGuide:button.tag];
[UIView transitionFromView:self.view
toView:guideController.view
duration:1.0
options:UIViewAnimationOptionTransitionCurlDown
completion:^(BOOL finished){
UITabBarItem *tabBarGuide = [[self.tabBarController.tabBar items] objectAtIndex:1];
[tabBarGuide setEnabled:TRUE];
self.tabBarController.selectedIndex = 1;
}];
[guideController release];
}
// End (IBAction)loadGuide
This works really well, up until the point where I then have to enable the Guide tab and switch to it. What happens at that point seems to be that another instance of the GuideViewController is created and replaces the one that was initially instantiated and transitioned to from the HomeViewController as shown above.
So I thought maybe I could work around it by, instead, moving the guide-loading to a new view, on that isn't used with the UITabBar, then load and transition to this view from the Home tab, just like I did in the above code. Then, after switching tabs, I'd need to somehow recall it into my Guide tab's view controller, as a subview or the like.
I'd think the view would still exist in memory after the tab-switching process, I just don't know how to access it, so I can show it again after the Guide tab's view has hidden it. Should I assign the view to some sort of globally accessible variable from the HomeViewController so that I can then access it from the GuideViewController (Guide tab's view)?
I'm open to any alternate suggestions as well, if you think this approach is bad form! I initially tried to overcome the problem by loading the details of the active guide into the database, then recovering that data when the Guide tab's view controller kicked in. However, the Guide tab's view must be cached or something, because if the user goes back to the home page and chooses a new guide, it'll animate the transition to that guide, but then when the Home-to-Guide-tab-switch kicks in, it flips back to the same state that the Guide tab's view was in before the user went back to the home page to choose a new tab. Also, I noticed the ViewDidLoad method doesn't get called again when manually nor programmatically switching tabs, so I figured that the other view must still be around in memory too! (The "other view" being either the original instance of the GuideViewController's view initiated from the Home tab upon selecting a guide button, or a new view as previously mentioned that would essentially do the same thing, albeit in a separate class.)
So to summarize:
I have two tabs, Home and Guide
Home has several UIButtons that when tapped will load a specific guide
When a UIButton on Home is tapped, it transitions from the Home tab's view to the Guide tab's view view CurlDown, without first switching to the Guide tab because that would lose the CurlDown effect
Then I have to trigger the tab switch programmatically, which seems to load a new instance of the Guide view, which effectively covers up the other instance
I want to know if I can somehow just call back up the first instance by somehow maybe storing the other instance as a global or some such?
Hense the question about how to pass a UIView instance around several UIViewControllers
If I were you I'd ditch the transition and just the tabbar as normal.
Firstly as it's giving you problems, but also and more importantly as it would seem strange to the end user who is used to tab bars just switching when you press the tab (well it would to me).
I'd read and re-read Apple's HIG on tabbars too. I think your users will find it very confusing that something other than the tab bar buttons causes the selected tab to switch.
You would have the data in the model.
The home tab would specify to the model which guide is chosen.
The guide would view load it's data every time it appears.
If you do need to keep the transition, then ditch the guide tab and use a navigationbar inside the home tab. You mention that screen space is the one issue for not doing so, but you can have the navigation bar present but not visible. You could then have a button in the guide tab to close that viewcontroller (pop the guide vc).
Another option might be to present the guide view modally instead - but the partial page curl also restricts screen space a little.
The ideal approach to doing this is to store a retained reference to the UIView object in a persistent object such as the app delegate subclass UIApplicationDelegate. The app delegate can then instantiate the view. Then, each controller needing to show the view would just ask the app delegate for the view. Also, if a root view controller is always available, it could be retained there as well.

UINavigationController 'menu'

I am trying to create a 'book style' interface. I have a plist which holds an array telling me which view controller is the next 'page'. So I check that, push the page onto the stack and fill it with info from the plist.
I also need a 'menu' button though so that users can quickly jump between pages. This is pretty simple but if the users jumps form page 1 to 3 for example and then uses the back button it will obviously pop back to 1. I need it to pop to page 2 though.
What is the best way to accomplish this? I have tried popToViewContorller: animated: but get the error telling me that the vc I'm trying to pop to does not exist.
Ok what you need you need to push each page for reaching your desired page means
suppose you want to go 4 page from 1 page then what you need set a integer variable(make it property in app delegate class) according to you view number.
then push next view according to your plist then check this your desired page (by checking your page number save in property and current page number). if yes then remains there otherwise push other one.(this will done viewDidLoad of each page).
Remember when you got your desired page then set that bool variable to NO;
For managing page number add one more thing in plist thats page number with that and then make your logic.
I dont think u can do it by poppingViewControcollers.Its that in ur navigationController.viewControllers array u will just have page1 at zero index & page3 at 1 index.When u do popToViewContorller: animated: its takes you to just immediate previous navigationController viewController that its being loaded like in ur case its page 1 is loaded before page3.
Maybe what you want is not a UINavigationController at all? It is designed to manage a stack of view controllers, but what you want is a list of controllers.
You can make your own custom subclass of UIViewController that manages an array of sub view controllers, populating a UIScrollView with the views from the managed view controllers.
This way the UIScrollView can:
Handle paging for you
Back, forward and even jump is simply a matter of setting the contentOffset.
You say you have all the view controller in a plist, so they can not be too many. So no need to worry about dynamic creation and complex life-cycle management of the managed view controllers.

Loading an external view controller, from a button click on another view controller

Im officially getting annoyed with objective-c and xcode now. Programming in PHP and Java is so much easier haha.
Anyway I could do with some help.
I have created a tab bar application with three tab items for the iPhone, on one of the items it loads a nib named mapView, this contains a button that I want to use to load up another nib named OverlayViewController.
Ive been following this tutorial this tutorial
to create a camera overlay. I understand how it works, but I don't understand how to run the view controller from a button or direct from the tab bar. I can only get the overlay to work if I load it like in the example on application launch in the app delegate. If I try and load it from the tab bar item I just get a grey screen, looks like the blank view controller is loaded and the code hasnt been run to show the overlay.
If anyone can suggest how I would go about loading the overlay from the button click, or even direct from the tab bar item I would be really grateful.
Thanks Alex
p.s. Heres the link to the project if you wish to view the files
#AlexApps I took a look through your project and have several pieces of feedback.
I think before you get too into trying to get the OverlayViewController working you should back up a bit and give some of the Apple docs a read, especially the View Controller Programming Guide. The Apple docs are for the most part well written and should help you gain a better understanding of views and view controllers than what is evident in your code.
Another suggestion is to grab some of the freely available source code from a book such as Beginning iPhone Programming which has a good example of how to lay out a tabBarController based app. I am sure there are other good samples out there that will show you how to organize your views and view controllers to load them into the different tabs.
I think that if you follow this advice that by the time you have restructured your app by what you learn you will have less problem doing what you are trying to do.
BTW, you may want to consider using a NavigationViewController for what you are trying to do with loading the OverlayViewController with a button press but take a few hours, slow down and do some focused reading. It will make a world of difference. Then if you have more specific questions, Stack Overflow (and Google) are your friends.
One last tip, you do not need to put IBOutlet in your instance variables AND in your properties, just one or the other, and really, you don't even need the instance variables at all anymore. I usually just use properties for everything.
I have done it with storyboard and the solution is to create a segue between the tab bar view controller and the view controller you want to load, then you have to put an identifier to that segue. Finally, in the method called when the button is pressed you have to put this:
[self performSegueWithIdentifier:#"segueId" sender:sender];
I have done it right now and it works perfect!
First import uiviewcontroller class in frist page like below:
#import "page2viewcontroller.h"
on button click event code below:
page2viewcontroller *page2 =[page2viewcontroller alloc] ;
[self presentModalViewController:page2 animated:NO];
[page2 release];
after back page2viewcontroller to page1viewcontroller same as like below:
#import "page1viewcontroller.h"
on backbutton click event code below:
page1viewcontroller *page1 =[page2viewcontroller alloc] ;
[self presentModalViewController:page1 animated:NO];
[page1 release];
That's all....!

Multiple View Controllers. Is there a maximum?

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.