Return for the first view after I'm on the fifth view of an iOS application in Xcode - xcode

I'm fairly new to xcode, and am creating a single view application with five views (xib files). I am not using navigation controller or storyboard for two reasons.
If I use Storyboard, I am forced to have my other views be UIView files. These dont have
-(void)viewDidLoad
Which prevents me from loading a few timers I have in my application.
I am able to navigate from the first page to the second and so on, all the way to the fifth page/view with the following code.
-(IBAction)pagethree {
countdown=[[Countdown alloc] initWithNibName:#"Countdown" bundle:nil];
[self.view addSubview:countdown.view];
}
However when I want to go back from the fifth view to the first page I run into a problem.
My first view is called ViewController. If I try the code from above, my app is full of errors.
I also tried using
-(IBAction)back {
[self.view removeFromSuperview];
}
but that only took me back one view.
My fifth view controller is called Statistics and the first one is called ViewController.
What can I code to get from back from the last view to the first?
Thanks

First, to answer your question, you need to do a removeFromSuperview (or similar) for each addSubview: you did. Each time you do addSubview, you're placing your new screen "on top" of the last one, like a stack. When you reach your 5th view, you have 4 other views "behind" it. (Actually, that's not exactly what addSubview does, but I'm just describing the effect in your particular situation).
But I think you're doing it wrong... You should read more about storyboards and navigation controllers. Both are used with UIViewController and support out of the box what you're trying to do by hand. For example, using a navigation controller, to push a new view controller you can do:
[navigationController pushViewController:viewController animated:YES];
You can do that as many times as you want. Then, to go back once, you do:
[navigationController popViewControllerAnimated:YES];
And to go back directly to the first one:
[navigationController popToRootViewControllerAnimated:YES];
Hope this helps.

Related

What is the best way to develop applications using the auto layout in Xcode?

So I guess this is going to be closed for being too subjective and too opinion based but if anyone can help me I would appreciate it.
I got a question. If I have a few controllers that all have almost the same thing For example they have the same background, have a menu going around the edge but the actual content is different. I had a couple of ideas. 1) Just have one view controller and just kill the objects for that current view if the user chooses a different option on the menu and spawn the new objects for that menu. My issue with this way was that I could't find a way to use the auto layout with this.
Second way would to be have a function in a .swift file that I can call and it creates an image view and sets up the menu an everything like that. I have the opposite issue here though, now the auto layout won't work.
App devs must have a way of doing this, I'm just probably thinking of this completely the wrong way.
Is there a better way to be doing this - I am sure there is? I would appreciate it if someone could point me in the correct direction.
Thanks
EDIT:
I should make it clear that the language I am using is swift.
You can create custom container view controller and swap the view controllers for the part that change according to the user selection.
--Adding Example--
e.g iPad's Settings app. The left side is a table view and right side is detail view which changes on user selection. So Tableview can be wrapped in a view controller let's say ListViewController. This will not change. The right side will be DetailViewController which would be swapped according to user selection. Your ContainerViewController will have 2 view controllers at all times.
Here is how to add view controllers as child and set their views in objective-c.
- (void) setupContentViewControllerWith: (DetailViewController*) detailViewController andListViewController:(ListViewController*)listViewController {
[self addChildViewController:listViewController];
[self addChildViewController:detailViewController];
listViewController.view.frame = CGRectMake(kListView_X, kListView_Y, kListView_Width, kListView_Height);
detailViewController.view.frame = CGRectMake(kListView_Width, kDetailView_Y, self.view.bounds.size.width, self.view.bounds.size.height-kDetailView_Y);
[self.scrollContainer addSubview:listViewController.view];
[self.scrollContainer addSubview:detailViewController.view];
[self.scrollContainer setContentSize:CGSizeMake(kListView_Width+self.view.bounds.size.width, self.view.bounds.size.height)];
}
When user selects new item from the list, you can swap DetailViewControllers as below
- (void) replaceEpisodeControllerWith:(DetailViewController *)detailViewController {
detailViewController.view.frame = CGRectMake(kListView_Width, kDetailView_Y, self.view.bounds.size.width, self.view.bounds.size.height-kDetailView_Y);
[UIView transitionFromView:currentDetailViewController.view
toView:detailViewController.view
duration:0.0
options:UIViewAnimationOptionTransitionNone
completion:^(BOOL finished)
{
[currentDetailViewController.view removeFromSuperview];
[currentDetailViewController removeFromParentViewController];
[currentDetailViewController release];
currentDetailViewController = detailViewController;
}];
}
I don't have swift version of this.

Clear memory of previous ViewControllers when using modal segues?

I've been working a photo editing app that takes pictures and passes it on to the
next view controller.
Of course I use AVSession to have the camera preview shown.
When the picture is taken the current view controller passes the image on to the view controller that has all the editing features.
I use modal segues to control transition between views.
The Problem is that when the segue happens there is a increase in memory by 4mb that never gets released.
Viewcontoller-->EditorViewcontoller
EdiorViewcontroller-->Viewcontroller
I also have a segue from the editor to camera,again there is a accumulation of memory.
A few times back and forth and the app crashes.
I can't post picture due to lack of reputation.
How can I clean the memory of the previous Viewcontroller and just have the current view controller running.
Things I've tried
*setting all the instances to nil.
*dismissing the view controller.
*setting the entire view controller to nil.
*profiled it.
*using #autorealease.
*spent hours on the internet searching for a solution.
I use this line of code to perform the segue.
[self performSegueWithIdentifier:#"effectsegue" sender:self];
I even tried using a weak self hoping it might help.
__weak ViewController *weakself=self;
[weakself performSegueWithIdentifier:#"effectsegue" sender:self];
When I profile it,it tells me these lines of code
NSData *jpegData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
and
[self performSegueWithIdentifier:#"effectsegue" sender:self];
are taking memory.
I would like some suggestions and idea as to what can be done to clear memory of previous view controller and free memory,any other alternates other than segues.
I've been working on this for weeks and this is really not allowing me to proceed forward.
Thanks in advance.
If you're using storyboards and ARC you can create a button inside EditorViewcontroller (that you'll use to go back to Viewcontroller) and link it to the following action on your EditorViewcontroller.m file:
- (IBAction)goBack:(UIButton *)sender
{
[self dismissViewControllerAnimated:YES completion:nil];
}
This should release the memory used by EditorViewcontroller

dismiss multipleViewControllers in iOS 5 and above?

I've an app which consists of a UITabBar with three views one of which is a UITableVIew. The first view that loads when the app boots is a UIView held within the UITabBar view. This view is a form for the user to fill in which takes them through five different screens. Previously I've been loading these as modal views one on top of the other and at the end dismissing them all when the user hits the final button like so:
[self.parentViewController.parentViewController.parentViewController.parentViewController dismissModalViewControllerAnimated:YES];
However since [self.parentViewController dismissModalViewControllerAnimated:YES] no longer works and has been replaced with [self dismissViewControllerAnimated:YES completion:nil]; I'm not really sure how to achieve this multiple dismissal of view controllers. I've tried adding the calls to parent view controller but that doesn't work. I've also tried:
[self.presentingViewController.presentingViewController.presentingViewController.presentingViewController.presentingViewController dismissViewControllerAnimated:YES completion:nil];
But that doesn't seem to work either. Any advice would be much appreciated. I'm also getting the message in the console: Application windows are expected to have a root view controller at the end of application launch. Is this what's causing the problem?
Please note, this is the first time in ages I've been programming for iOS, I've been devoting most of my time recently to Arduino and interfacting electornics with coding so this is a bit of a steep refresher course I'm on.
Help would be much appreciated.
If your five view controllers are pushed onto a UINavigationController, then they can all be dismissed/popped with one command:
- (NSArray *) popToViewController: (UIViewController *) viewController
animated: (BOOL) animated
[It doesn't appear that you are using a UINavigationController... but it wasn't entirely clear from your description.]

What is the pattern of navigating between UIViewControllers in iOS?

I have a bunch of UIViewControllers subclasses (let's call them MainForm, DetailForm, MoreMinorDetails). Basically the idea is that AppDelegate class instantiates MainForm, user presses some type of button on MainForm and DetailForm comes up. Then on a button on the DetailForm launches MoreMinorDetails. And of course, I should be able to go back down to the MainForm.
Note that there aren't any UINavigationController objects anywhere in sight.
What is the accepted pattern to move between UIViewControllers in a manner described above?
Or am I going about it in the wrong way?
I'll be happy with either XCode or MonoTouch based explanation.
You can use a UINavigationController and hide the navigation bar:
self.navigationController.navigationBar.hidden = YES;
Then in your button's action just push the next view controller:
-(void)buttonAction:(id)sender
{
NextViewController *nextViewController = [[NextViewController alloc] init];
[self.navigationController pushViewController:nextViewController animated:YES];
}
To go back, use
-(void)goBack
{
[self.navigationController popViewControllerAnimated:YES];
}
To go to a certain view controller (you have to know exactly when it was pushed onto the navigation controller's stack):
-(void)goToViewController
{
[self.navigationController popToViewController:[self.navigationController.viewControllers objectAtIndex:1] animated:YES];
}
Or to pop to your root view controller
[self.navigationController popToRootViewControllerAnimated:YES];
This way, you will obtain the UINavigationController's functionality and keep all the space in the view.
AngryHacker,
My simple suggestion is to follow zoul one. I think the simplest way to achieve what you want it' to create a UINavigationController and use it as a containment controller for other controllers.
So, the way could be create a UINavigationController in the AppDelegate and set it as the rootViewController for your window. When you create a UINavigationController you can pass to it a root controller (in this case MainForm).
In MT it looks like the following (do not trust the code because I've written it by hand)
private UINavigationController navController;
public override bool FinishedLaunching (UIApplication app, NSDictionary options)
{
navController = new UINavigationController(new MainForm());
window.RootViewController = navController;
window.MakeKeyAndVisible ();
return true;
}
Now, when you launch the app you will see the MainForm's view and will able to allow navigation among different controllers.
For example, within MainForm you can go to DetailForm like:
this.NavigationController.PushViewController(new DetailForm(), true);
The same applies within DetailForm to MoreMinorDetails.
To go one step back, for example from MoreMinorDetails to DetailForm use
this.NavigationController.PopViewControllerAnimated(false);
To go to the the root controller (MainForm) within DetailForm or MoreMinorDetails use
this.NavigationController.PopToRootViewControllerAnimated(false);
About the space, it's not a problem. I guess you have two ways. The first is to move the bar items you have created within the navigation controller bar. In each controller you can decide what buttons make visible or not. The second is to hide completely the navigation bar and use the button you've already created.
In both ways you can attach actions to these buttons and allow the navigation between controllers. Furthermore, if you choose the first you can also hide the back button for your navigation bar.
A simple note to take in mind is the following:
Since the navigation bar is unique for a UINavigationController, the bar will maintains its state for all the controllers you push in the navigation controller. To explain the concept suppose you have two controllers, say A and B. You first push A and in its ViewWillAppear method you hide a button. When you push B, the button still remains not visible. If you want to unhide the button in B, you can play with its ViewWillAppear method (like before) and so on...
If you don't want to play with UINavigationController you should take a look to new view controller containment functionality provided by UIViewController class. This applies only from iOS >= 5. You can obtain the same effect of UINavigationController mechanism but it could be more difficult to achieve.
Hope that helps.

NSView added as subview doesn't show

I have a puzzling problem. Working on a cocoa app in mac os x 10.7.
My app main window contains a split view. In a certain use context in one of the subviews of the split view is loaded a custom view with some labels (nstextfield) and a split view (instantiating a view controller that loads a nib and getting view from that controller). Frame of the custom view is set to split view subview bounds and everything works fine.
Problem is that one of the subviews of the second split view should be loaded (same method: view controller-nib-view-frame/bounds) with a custom view containing a table view and a button, but in this case nothing shows. Everything is done the same way but last custom view is not visible. Any idea?
Thanks
(edit)
this is the code I use to instantiate controller for the view to be added, get the view, and add it as subview to a subview of the split view
- (void)loadSubview {
self.subviewToAddController = [[viewController alloc] initWithNibName:nil bundle:nil];
//nib name is coded in the controller class definition
[[self.subviewToAddController view] setFrame:[self.splitViewContainerSubView bounds]];
//container subView is an outlet
[self.splitViewContainerSubView addSubview:[self.subviewToAddController view]];
}
However I don't think the problem is in this code because if I ask the container subview for its own subviews I can see the new subview is present in the list. It just doesn't show. If I add it as a subview of the split view (a test a just made) or as subview of the subview of the most external split view it is correctly showed too (sorry for the confused explanation, I would need a diagram but in this moment I can't make it)
To elaborate more my doubt (I didn't want to misled so I didn't mention before) can't it be a problem of coordinates, so view is correctly loaded and added as subview but is not visible because hidden by something or showed out of visible area?
(update)
Sorry it took so long to post an update.
After more testing I found out the problem is related to autolayout. No idea what the exact problem is and how to solve it. I ended up turning it off for the nibs the were in troubles and use the old way to set interface objects position and size/resize. Not the best way but for now I can go on.
My best guess is that you didn't set the autoresizing masks of the view properly.

Resources