ViewController being held in memory - ios

I use the following code to switch between view controllers..(works fine) I have many view controllers too by the way Im not just switching back and forth between 2
NSString * storyboardName = #"Main";
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:storyboardName bundle: nil];
MyTableViewVC *detailView = (MyTableViewVC *)[storyboard instantiateViewControllerWithIdentifier:#"MyTableViewVC"];
//pass data through to VC
[self presentViewController:detailView animated:NO completion:nil];
I see the memory use climbing as I transition between view controllers
So i did some research and realized Im not dismissing the previous view controller. I use the following code [self dismissViewControllerAnimated:NO completion:nil]; before I call presentViewcontroller: (I also tried using it after) and it doesn't work. If i use it after nothing happens.. using it before I get the following warning
Thread 1:EXC_BAD_ACCESS(code=1.... blah blah let me know if you need the rest
Ive also tried to do something like this..
[detailView presentViewController:detailView animated:NO completion:nil];
[self dismissViewControllerAnimated:NO completion:nil];
What am I doing wrong?

Below is the code to remove VC from the navigation stack.
NSMutableArray *navigationArray = [[NSMutableArray alloc] initWithArray: self.navigationController.viewControllers];
// [navigationArray removeAllObjects]; // This is just for remove all view controller from navigation stack.
[navigationArray removeObjectAtIndex: 2]; // You can pass your index here
self.navigationController.viewControllers = navigationArray;
[navigationArray release];
However note, by doing this you will have problem to go to previous VC as you are removng the previous VC from the stack.
As you are complaining about memory, I would say DOUBLE CHECK code once again and investigate where memory is getting used more. Incase if that object is not needed, release that object so that memory issue would not be there.

If you want to back to root view controller, you must use this code.
[self.navigationController popToRootViewControllerAnimated:YES];

Related

Xcode Can't Call/Dismiss viewcontroller from PopUp

This is going to take some explaining... So I'll do it in order:
I have a navigation controller where the rootViewController is called TipsCollectionViewController.
I have a UserViewController that's loaded as a popup:
UserViewController * userView = [[UserViewController alloc] initWithNibName:#"UserView" bundle:[NSBundle mainBundle]];
[userView setUEmail:email];
[self presentPopupViewController:userView animationType:MJPopupViewAnimationSlideTopBottom];
I then have another popup that loads on top of THAT popup:
Place *p = [placeArray objectAtIndex:indexPath.row];
DetailPlaceViewController *pvc = [[DetailPlaceViewController alloc] init];
[pvc setPlace:p];
NSLog(#"%#", p.PName);
[self presentPopupViewController:pvc animationType:MJPopupViewAnimationSlideTopBottom];
Now there's a reason I've done this: the AppDelegate features a Navigation controller and previously I loaded the UserView like this:
[self.navigationController presentViewController:userView animated:YES completion:nil];
But this meant that the UserView would load on the iPhone but not on the iPad for some odd reason. But when I switched it to the popup view it worked fine.
So now I load both the UserView and the DetailPlaceView in a popup... but now it CLOSES on the iPad but not on the iPhone.
Here's the code for closing the detail view:
- (void) didTapBackButton:(id)sender {
NSLog(#"View Controller Number: %lu", (unsigned long)self.navigationController.viewControllers.count);
if(self.navigationController.viewControllers.count > 1) {
[self.navigationController popViewControllerAnimated:YES];
NSArray *stack = self.navigationController.viewControllers;
TipCollectionViewController *tipsVC = stack[stack.count-1];
[tipsVC.collectionView reloadData];
}
I know there's a better way to handle this whole thing... but what should I be doing differently?
UPDATE
If I switch it back to:
[self.navigationController pushViewController:userview animated:YES];
...for the UserView on the iPhone and:
[self.navigationController pushViewController:pvc animated:YES];
...for the view that loads after that, then the UserView will load... but the next viewcontroller (the DetailPlaceViewController) won't load. I think that's my main problem. I could probably dismiss the second view controller at that point if I could get it to load. Any ideas?
[self presentPopupViewController:pvc animationType:MJPopupViewAnimationSlideTopBottom];
if you are using this,presentPopupViewController is used to display like modal view which cant be dismissed without any custom cancellation action.
To use popOverViewController method, use pushViewController. Then that one you can dismiss by this technique.
Ultimately all I had to do was switch:
[self.navigationController pushViewController:pvc animated:YES];
to:
[self presentViewController:pvc animated:YES];
And it works. It opens and closes the view and everything works as it should.
I'm getting a warning on the DetailView once you click an item:
Presenting view controllers on detached view controllers is discouraged <UserViewController: 0x16e02020>
So I'll wait a couple of days to accept my answer. Otherwise, despite the warning, it seems to be working.

How to switch back to the Main view i.e ViewController.h" what is the nib name for MainStoryboard.storyboard?

I use the following code to switch from main view (ViewController.h)to another view (TouchViewController) and then similarly switch from this view to the next view (QuestionsViewController).
How do I go back to the main view from here? i.e what is the value for initWithNibName for MainStoryboard.storyboard?
- (IBAction)startGame:(UIButton *)sender {
TouchViewController *second = [[TouchViewController alloc] initWithNibName:#"TouchViewController" bundle:nil];
[self presentViewController:second animated:YES completion:nil];
}
and
- (IBAction)selectTopic:(UIButton *)sender {
NSString *category = [[sender titleLabel] text];
[[NSUserDefaults standardUserDefaults] setObject:category forKey:#"MyKey"];
QuestionsViewController *second = [[QuestionsViewController alloc] initWithNibName:#"QuestionsViewController" bundle:nil];
[self presentViewController:second animated:YES completion:nil];
}
Now to go back to the main view i have a problem i.e
- (IBAction)backtoMainMenu:(id)sender {
ViewController *second = [[ViewController alloc]initWithNibName:#"MainStoryboard.storyboard" bundle:nil];
[self presentViewController:second animated:YES completion:nil];
}
At this point the app just crashes! I suppose it's because initWithNibName:#"MainStoryboard.storyboard" can't be used but the ViewController does not have any other xib file - so what do I do?
First of all storyboard can't be used as a xib file they are not the same thing. Second you have one view controller that presents a view controller that also present a view controller so what you can do is something like this from the third view controller:
[self.presentingViewController.presentingViewController
void)dismissViewControllerAnimated:YES completion:nil];
This is the fastest way you can do it, but it's not really reusable, if you have a more complex view controller hierarchy than it will be really ugly to do it like this, other solutions can be delgates or notifications.
Also just a piece of advice, when you want to go back to a previous screen in general you don't what to create a new view controller (as you try in backToMainMenu method, you simply want to remove all the view controllers (screens) until you reach the desired screen.

Push a new ViewController and Pop the last one from NavigationStack

Hey Guys i want to push a new controller onto the navigation stack and then remove the controller where i pushed from.
Here is my Code :
WishDetailViewController *detailView = [self.storyboard instantiateViewControllerWithIdentifier:#"WishDetailView"];
detailView.transferWishID = [NSNumber numberWithFloat:[[response objectForKey:#"id"]floatValue]];
[self.navigationController pushViewController:detailView animated:YES];
[self.navigationController popViewControllerAnimated:NO];
Everthing works fine, but i got this message here inside the console :
2013-02-05 10:32:42.029 BWMApp[1444:1a603] nested pop animation can result in corrupted navigation bar
2013-02-05 10:32:42.392 BWMApp[1444:1a603] Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
So what i am doing wrong and how can i prevent my app from throwing this error message ?
You can use setViewController. This example removes all and insert others, but give you the basic idea :)
NSMutableArray *viewCons = [[[self navigationController]viewControllers] mutableCopy];
[viewCons removeAllObjects];
[viewCons addObject:portraitTemp];
[viewCons addObject:self];
[[self navigationController] setViewControllers:viewCons];
There is no need to pop the "old" viewcontroller. The navigationController create a backbutton automatically. if you pop the viewcontoller from the stack there is no viewcontroller to "jump" back. This is the cause of message inside the console. The navigationController can't work correctly.
WishDetailViewController *detailView = [self.storyboard instantiateViewControllerWithIdentifier:#"WishDetailView"];
detailView.transferWishID = [NSNumber numberWithFloat:[[response objectForKey:#"id"]floatValue]];
[self.navigationController popViewControllerAnimated:NO];
[self.navigationController pushViewController:detailView animated:YES];

How and where would you use instantiateViewControllerWithIdentifier

UIStoryboard *mainStoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard"
bundle: nil];
MenuScreenViewController *controller = (MenuScreenViewController*)[mainStoryboard
instantiateViewControllerWithIdentifier: #"<Controller ID>"];
Where exactly do i write this code if i have to make sure that the current view is instantiated with the identifier? Which means if i write any code on this class it has to appear when this viewcontroller loads? Also how would i use it? I dont want to create an instance of the menuscreenviewcontroller. WHich means i have to say self but i used self.view and that doesnt work.
You need to push or present the view controller that you have created. You can not directly change views of the controllers by instantiating.
For example you need to use this code to trigger the transition (maybe a button action):
MenuScreenViewController* controller = (MenuScreenViewController*)[ourStoryBoard instantiateViewControllerWithIdentifier:#"<Controller ID>"];
controller.controlFlag = YES;
controller.controlFlag2 = NO; // Just examples
//These flags will be set before the viewDidLoad of MenuScreenViewController
//Therefore any code you write before pushing or presenting the view will be present after
[self.navigationController pushViewController:controller animated:YES];
// or [self presentViewController:controller animated:YES];
As per Uğur Kumru's answer, with a small edit: if you are not using a Navigation Controller, and you are developing against iOS 5.0+ you will need to use:
MenuScreenViewController* controller = (MenuScreenViewController*)[ourStoryBoard instantiateViewControllerWithIdentifier:#"<Controller ID>"];
[self presentViewController:controller animated:YES completion:nil];
If you omit the completion:nil you will face errors

Calling popToRootViewControllerAnimated after dismissModalViewControllerAnimated

I am working application in which i calling presentModalViewController and once finished(calling dismissModalViewControllerAnimated:YES) it should immediately call popToRootViewControllerAnimated.
But the issue is dismissModalViewControllerAnimated:YES is working properly but popToRootViewControllerAnimatedis not working after it.
The code is shown below:
[self.navigationController dismissModalViewControllerAnimated:YES] ;
[self.navigationController popToRootViewControllerAnimated:YES];
Try something like this:
[self.navigationController dismissModalViewControllerAnimated:YES] ;
[self performSelector:#selector(patchSelector) withObject:nil afterDelay:0.3];
-(void)patchSelector{
[self.navigationController popToRootViewControllerAnimated:YES];
}
It is not so neat but it should work.
UPDATE:
You should use
[self dismissModalViewControllerAnimated:YES];
instead
[self.navigationController dismissModalViewControllerAnimated:YES] ;
The object that is presenting the modal is the view controller, not the navigation controller.
If you have a navigation controller with a stack of UIViewControllers:
[self dismissModalViewControllerAnimated:YES];
[(UINavigationController*)self.parentViewController popToRootViewControllerAnimated:YES];
//UIViewController *vc = [[UIViewController new] autorelease];
//[(UINavigationController*)self.parentViewController pushViewController:vc animated:YES];
Assumes, that view controller in which called modal view controller has navigationController.
I ran into something similar to this. You need to make a copy of your self.navigationcontroller first and also retain yourself, so when you call the second pop, there is still a reference to the NC and you still exist.
// locally store the navigation controller since
// self.navigationController will be nil once we are popped
UINavigationController *navController = self.navigationController;
// retain ourselves so that the controller will still exist once it's popped off
[[self retain] autorelease];
// Pop this controller and replace with another
[navController popViewControllerAnimated:NO];
[navController pushViewController:someViewController animated:NO];
see : How can I pop a view from a UINavigationController and replace it with another in one operation?
I guess, you are not calling the
[self.navigationController popToRootViewControllerAnimated:YES];
in the target modal viewcontroller. check that.

Resources