I have a tab bar application. Each tab contains navigation controller allowing the user to transition from one view to the other. Each view is being handled by a view controller and each view controller class has -didReceiveMemoryWarning method.
Problem: When I use "Hardware > Simulate Memory Warning" option of iPhone Simulator in any model viewcontroller after after that if I want to dismiss that controller using -
[self dismissModalViewControllerAnimated:YES]
Then, viewDidLoad method is not called for the controller to which I have added that model view controller, and app crashes there.
Any idea, what I'm doing wrong.
Probably this will be because, in viewDidLoad method u r not taking care of all the released object.In simulate memory warning , we have to release all those object , which can be loaded in viewDidLoad.
Related
In my app I would like to show a login screen - which will be displayed when the app starts and when the app becomes active. For reference, I am using storyboards, ARC and it is a tabbed bar application.
I therefore need to do the process in the applicationDidBecomeActive method:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
if ( ... ) { // if the user needs to login
PasswordViewController *passwordView = [[PasswordViewController alloc] init];
UIViewController *myView = self.window.rootViewController;
[myView presentModalViewController:passwordView animated:NO];
}
}
To an extent this does work - I can call a method in viewDidAppear which shows an alert view to allow the user to log in. However, this is undesirable and I would like to have a login text box and other ui elements. If I do not call my login method, nothing happens and the screen stays black, even though I have put a label and other elements on the view.
Does anyone know a way to resolve this? My passcode view is embedded in a Navigation Controller, but is detached from the main storyboard.
A variety of answers finally led me to an answer which doesn't seem too complicated so I will post it here - and it actually looks really good if I am honest.
Firstly, my password view is embedded in a Navigation Controller (Editor -> Embed In) and this is connected to the main tab bar controller using a modal segue with an id, in my case 'loginModal'.
In the applicationDidBecomeActive method put something like this:
[self performSelector:#selector(requestPasscode) withObject:nil afterDelay:0.2f];
And then put this function somewhere in the App Delegate
-(void)requestPasscode{
if ( /* If the user needs to login */ ) {
[self.window.rootViewController performSegueWithIdentifier:#"loginModal" sender:self];
}
}
This will present your login view whenever the app begins or enters the foreground (for example, when switching apps).
NOTE: The above line will not work if the root of your app is embedded in a navigation controller.
There are however two bugs;
If the user was previously viewing a modal view when they dismissed the app
If the user dismissed the app on the password view.
Both of these cause the app to crash so the following line goes in the applicationWillResignActive method.
[self.window.rootViewController dismissViewControllerAnimated:NO completion:nil];
It basically dismisses all modal views that are presented. This may not be ideal, but modal views are more often then not, used for data entry and so in many cases, this is a desired effect.
You should init PasswordViewController viewcontroller from xib or if you store UI in Storyboard you should use Segue for present this controller.
I can't say about another parts but that part seems to me very weird.
My passcode view is embedded in a Navigation Controller, but is detached from the main storyboard.
in storyboards you can store view controllers and view inside of view controllers so it's not good to store some view outside of viewcontroller because you will not be able to load this view from storyboard after receiving memory warning. Please correct me if I didn't get what do you mean.
If we are going by your way there is no difference load PasswordViewController at applicationDidBecomeActive or at your first view controller at Storyboards because you calling present view controller from first loaded view controller. So you can do it in your first view controller. Also you can store some hidden view inside of your first viewcontroller and show this view if the user needs to login.
I tested it. So at first your controller become loaded and then you got method applicationDidBecomeActive. So it's better to put your code inside -(void)viewDidAppear:animated method of your first viewcontroller.
Best regards,
Danil
I have a uitabbar with 4 buttons. The start up screen loads as it should on the applications start. 2 of the buttons views don't load on start (good). 1 is a web view the other is a navigation controller with a table view. The last view does load on application start. It is another navigation controller with a table view.
I know which ones are loading and which are not because i added nslogs to the didload function on all top level controllers.
So the overall issue is that when i start my app, then rotate it, then go into the tabbar item that has already been loaded the header in the tableview which is a webview, never got the memo that it should have rotated, and therefore resized. Once your in the view if you rotate back and forth then it works as it should. Its just the initial time.
Update 1:
The question is how do I stop the 2nd controller that is on another button of the tab bar from loading on app start.
Update 2:
I do all my init stuff in didload but I tried adding the following code, but it never shows up in the log. I am not using IB, this is all done programmatically:
- (void)loadView
{
NSLog(#"Loading feedback");
}
Update 3:
I figured out whats causing this. I do have a xib that houses my tabbarcontroller. In that tabbarcontroller i have a navigation controller, then i have a view controller (I set the class to my feedback class), then i had the navigation item and a table view. When i add the tableview it triggers the controller to load. Simply removing that will stop it form loading early. Then to fix it, i created a xib for the feedback. So I dont like having nibs that server a single purpose, in this case its to get a table view in there and have it be a grouped style. I may try to just manually add the tableview instead of having a tableview controller.
Its much easier to do in code. The tab bar controller accepts the view controllers in the array and the default tab bar controller is the one which is at the first index of the tab bar controller.
UITabBarController *tabBarController = [UITabBarController alloc] init];
tabBarController.viewControllers=[NSArray arrayWithObjects:firstViewConoller,secondViewController,nil];
[self.view addSubview : tabBarController.view];
Place all the view related task in viewDidLoad method sometimes loadView gies problem this may be because of your viewController trying to load a new view which calls itself again and again so better to add them to viewDidLoad.
The view controller for the tab that loads prematurely probably accesses the self.view property before it is needed needed.
If finding he access point is hard add a breakpoint to loadView, make a dummy overload only calling [super loadView] if needed (The view is loaded from a NIB). The breakpoints stack trace will show you where you force the load to occur.
I have a view in my app that displays a UITableView. This view is created in a nib file and has a custom view controller. The UIViewController subclass for this view acts as the Datasource and Delegate for the UITableView.
My UITableView displays several rows based on my data. Then, the last row displays different text: "Add another...". If the last row is selected, I present a modal view controller (to allow the user to add more data). When I dismiss the modal view controller, I again see the original view (as expected) and all appears to be well. However, when I try to interact with this view, the app crashes.
From placing several NSLog() statements through the UIViewController (for the UITableView), I have determined that the -dealloc method is being called just after the modal view is dismissed. This explains the crash when I try to do something with that view. However, I have no idea why -dealloc is being called on this view controller.
To dismiss the modal view controller, I have:
[self dismissModalViewController:YES];
As the code in an IBAction method in the modal view controller's UIViewController. This action is tied to a cancel button in the corresponding nib file.
In addition, my understanding from the View Controller Programming Guide is that it's OK to dismiss the modal controller from within itself, but it's more robust to use delegates. I was initially using a delegate, but took the delegate out to simplify debugging. I just put the delegate back in to double-check, and the same behavior occurs when using delegates. The modal controller's action method calls is implemented as:
[[self delegate] myModalViewController:self didAddObject:obj];
The delegate implementation in the parent view controller is:
[self dismissModalViewController:YES]
If anyone has seen this before or has any suggestions of what could be happening or how to debug this, I would greatly appreciate it.
If -dealloc is being called, something is releasing the view controller. Try implementing -release in your view controller:
-(void)release {
NSLog(#"view controller released");
[super release];
}
so that you can use the debugger to inspect the call stack when this unexpected release message happens.
Its dangerous to call dismissModalViewController from the modal view controller itself (message will be forwarded to parent view controller), if you have not retained it elsewhere. Normally, the parent view controller is responsible for dismissing the modal view controller it presented.
Trying to fix a very strange error, i have 3 view controllers that start from the app delegate and push each other accordingly. The 3rd view controller then has a toolbar button that calls the code here:
-(void)showEventBrowser;
{
accelManeger.delegate = nil;
NSLog(#"%u",[self.navigationController.viewControllers count]);
[self.navigationController popToRootViewControllerAnimated:NO];
}
This works the first time round but when i come back to this view controller and try again. Firstly it reports that there are 3 view controllers on the stack. It then deallocs the 2nd view controller in the stack and doesnt crash but will not go any further. If i hit the button again it says there are no view controllers on the stack and fails to respond.
I have logs for all the viewdid, viewwill, e.t.c in each view controller and there appears to be no odd behaviour. Also no memory warnings from any view controllers.
Why would this work once through but not the second time ?
Well i Fixed this.
I was trying to poptorootviewcontroller from a viewcontroller that had no view but isntead just displayed a UIImagepickercontroller. Even when attempting to dissmiss this modalviewcontroller first, (even with a delay), i still had the same problem. I instead changed the viewcontroller in question to a UIMagepickercontroller subclass and handle the present and dismiss in another viewcontroller.
Lesson learnt, dont pop to root with UIImagepickercontroller modal view ontop.
Using a navigation based view hierarchy. I have a root view controller, and multiple view controllers that branch out from the same when a button is pressed. When a user presses the back button on the UINavigationBar, the current viewcontroller is popped and the display animates back to the rootviewcontroller.
The problem is, I want the viewcontrollers to UNLOAD whenever they are popped. Seems like they are not unloading because when I go back to them they are still in the state they were when they were popped.
How do I unload the viewcontrollers after navigating back to the rootviewcontroller?
-viewUnload is called after the application receives low-memory notification.
It is the default implementation of -didReceiveMemoryWarning that calls -viewUnload.
What you probably want to do is put what you want to do into -viewDidDisappear based on what you've described.
When you pop a viewcontroller from a navigationcontroller, there should be no more references to the viewcontroller left and the viewcontroller should be deallocated at that time. This should give you the results you expected. You can test if the viewcontroller is being deallocated by adding a break point in -dealloc method.
If dealloc does not get called, check if there is a retain cycle. Specifically check if a child object is retaining the viewcontroller.
in -viewDidDisappear why not [self release]; just need to make sure you have a lazy loader so it will load back when needed.