dismiss multipleViewControllers in iOS 5 and above? - xcode

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.]

Related

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

Return for the first view after I'm on the fifth view of an iOS application in 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.

Storyboard in Xcode is so slow

I have 150 UIViewController in Storyboard and scrolling between these Views is so slow. I can't zoom in and zoom out easily and it takes some serious time to do sty.
I'm on MBPR and I installed Xcode 4.4
Spec: 2.3GHz / 16G / 256 which I think it's enough to handle such a thing.
Is there any options, settings, or tips/tricks to have so many views in storyboard and don't miss the performance.
NOTE: I've done all the possible solutions (deleting cache and workspace). Didn't work. It has something to do with number of UIViewController in Storyboard.
Thanks
Update 2016: Just to update this question as there is a new feature in Xcode 7 that allows you to refactor the Storyboard into multiple Storyboards.
Refactoring Storyboards
https://developer.apple.com/library/ios/recipes/xcode_help-IB_storyboard/Chapters/RefactorStoryboard.html
If you search the term "refactoring storyboards" you will find good tutorials :)
It is considered best practice to split up storyboards into lots of different modules (each one in a separate storyboard). It will take away these performance issues you are having and also has other advantages such as making it easier to manage in general (no massive SVN conflicts etc).
However I had another issue which was causing storyboard lag. I had approx 25 view controller and was receiving ALOT of lag - but only when Xcode was running on an external monitor.
I noticed that if I disabled "auto layout" for the storyboard, the lag would completely disappeared. I reverted this change, and then followed the following process:
-Delete a ViewController
-test if it still lags
-if still laggy revert changes
Eventually I found a certain ViewController which if deleted stopped all lag. I then reverted this and went through the views to see which view caused the lag. I eventually narrowed this down to a "UIButton" inside a "UIBarButtonItem". I believe I changed the "Type" property on the button, and then changed it back and the lag stopped. From SVN it seems like the frame was changed in the .storyboard file. After this point the lag never came back again.
TLDR:
Storyboard lag is not always because you have too many items in the storyboard. I managed to get rid of a lag problem by causing Xcode to re-do some layout.
Hope my experience will help someone else diagnose/solve their problems. I was working for about 0.5 years before I finally got really annoyed and tried to solve the issue.
Definitely use multiple storyboards for this. I am not aware of any limitations in using storyboards but trying to render all those UI code at one time is hard for your machine and it is also hard for developers to understand.
Try to logically divine your storyboards into categories such as: "profileSB, feedSB, mapSB, messagesSB, settingsSB"
Here are some good tutorials on the creation of these:
http://spin.atomicobject.com/2014/02/18/ios-storyboards-xcode5/
http://www.skillmasters.net/main/xcode-using-multiple-storyboards/
150 ViewControllers in one Storyboard sounds awful lot to me.
Try to minimize your flow or split into multiple storyboards if you really need so many
I had a UIStoryboard with 10 or more UIViewControllers and additional ContainerViews. After layouting the views and customizing more and more, the UIStoryboard got more and more lazy.
My approach was to setup the views inside single UIStoryboards. Loading the controllers is done inside my Menu, where I setup an NSArray with all identifiers for the UIViewController which also have to be setup inside the UIStoryboard:
When loading the menu, I loop through the NSArray and load the UIViewControllers by identifiers from the specific UIStoryboard. This is the place where I needed to implement a switch, for the different UIStoryboards:
self.arrayVCAll = [NSMutableArray new];
for ( NSArray *array in _arrayViewControllerAll ){
NSMutableArray *arrayTemp = [NSMutableArray new];
for (UIViewController *vc in array ){
NSString *strViewController = [NSString stringWithFormat:#"%#", vc];
UIStoryboard *storyboard;
if( [strViewController isEqualToString:#"CustomOneStoryboard"] ){
storyboard = [UIStoryboard storyboardWithName:#"FirstVC" bundle:nil];
} else if( [strViewController isEqualToString:#"CustomTwoStoryboard"] ){
storyboard = [UIStoryboard storyboardWithName:#"SecondVC" bundle:nil];
} else {
storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
}
UIViewController *controller = [storyboard instantiateViewControllerWithIdentifier:strViewController];
MyNavController *nav = [[MyNavController alloc] initWithRootViewController:controller];
[arrayTemp addObject:nav];
}
[self.arrayVCAll addObject:arrayTemp];
}
In my case, there was just a problem with the segues after separating the initial UINavigationController from my UIViewControllers. The segues won't push to a navigationController, if there is no initial UINavigationController. Thats why I added a UINavigationController on each UIViewController (of my NSArray) so the UIStoryboardSegue will be done correctly. The UINavigationController also doesn't need to be connected to a class, just include it inside the UIStoryboard and connect it to the first UIViewController.

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.

Setting view in NSSplitView not working

Please excuse my ignorance, I'm coming from iOS to Mac programming. I have two nibs. One is the main window with the split view. The nib contains a navigationController view I created. I'm trying to replace the right pane of the split view (navigationView) with this view. When the application first launches, navigationView is just a custom view in interface builder.
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NavigationController *navController = [[NavigationController alloc]
initWithNibName:#"NavigationController"
bundle:[NSBundle mainBundle]];
navigationView = navController.view;
}
This doesn't seem to do anything. I tried adding the navController.view as a subview, and that at least gets it showing up, but it is placed very oddly. Any suggestions? Thanks!
You will definitely have to add the views you want in the NSSplitView as a subviews of the NSSplitView. You'll need to provide more information about what happens after that.
There's lots of sample code on Apple's website and many of them use NSSplitViews.

Resources