[self viewDidAppear:YES]; - iphone

Does [self viewDidAppear:YES]; in the viewDidLoad section of code ensure that the viewDidAppear section of code will run?
Based on feedback from a small subset of our users, it appears for whatever reason that the code I have written in the viewDidAppear section of the main menu's view is not running for them - but it works perfectly well for the majority of users and in all my testing. I'm hoping that by adding [self viewDidAppear:YES]; this will fix the issue for those devices that for some reason were not calling viewDidAppear...
What do you guys think?

I think that's a horrible idea, personally. I think you're better off finding out WHY viewDidAppear didn't execute for that subset of users. You may only be treating a symptom of a greater problem by just 'fixing' what appears to be wrong.

ViewDidAppear may not be getting called if its on a view controller that is nested in another view controller and running on an older OS. Before iOS 5, delegate commands did not always get forwarded to child controllers.

You should never call delegate methods directly.

Related

three20 - TTTableViewController Memory warning gives blank screen, how to fix?

This is driving me nuts. I am using three20's TTTableViewController and when I get a memory warning, the screen goes white. Now, after reading on the three20 google group is seems that the tableView got released. But, I cannot for the life of me figure out a check to see if that is the case, then create it again.
I was using the following because I thought it would fix the issue, but it seems that it doesn't satisfy the if statement:
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
// If we don't have a datasource we need to reset it
if (!self.dataSource) {
// Create datasource again
}
}//end
Does anyone know what to do when this happens? The google group has been no help.
Are you subclassing TTTableViewController? I haven't used it before, but assuming it's just like UITableViewController...
How does your "viewDidUnload" look like? Are you releasing the tableview here? If so, you need to create tableview in viewDidLoad to match it.
No need to check if dataSource is available in viewDidAppear, because if you read View programming guide, it explains that memory warning will call "viewDidUnload" to give you a chance to clean up data that are created in "viewDidLoad".
i had the same issue and it drove me crazy as well.
Nobody mentions it in the three20 docs, but you shouldn't use UIViewController's initWithNibName function to add subviews. If you do, a memory warning will release these subviews.
Try to move your code from initWithNibName function to viewDidLoad function. I have noticed that some code need to be kept in the initWithNibName, such as navigation styles. However, any subviews added to the controller's view should be in the viewDidLoad function.
In general you should be careful to set up views in viewDidLoad rather than the class constructor. For instance, you should set up your launcher view in viewDidLoad rather than the constructor of your launcher view controller, otherwise your launcher will become empty after a memory warning.
In the case of TTTableViewController however this does not (usually) apply because you don't set up the table view manually. I had the same problem you had, and eventually tracked it down: I had redefined viewWillDisappear: and forgot to call [super viewWillDisappear:animated]. This meant that some of the flags that the Three20 controller maintains about the state of the view were not updated correctly.
I also found that it was beneficial to redefine didReceiveMemoryWarning to call [self setEditing:NO] before calling super; I found that the state of the table view got confused otherwise (this is not relevant if you don't use edit mode for your table).
Finally, there is a bug in Three20 which means that tables in loading/empty/error mode will not be restored properly; see a discussion in the blog post by TwoCentStudios and a proposed fix on github.

viewDidAppear called twice on the same instance, but only the first time this class loads form NIB

I have a navigation controller. One of the views adds custom subviews in its viewDidAppear:. I notice that the first time I navigate to an instance of this view controller after launching the app, viewDidAppear: invokes twice. If I pop this view off the stack and navigate to it again, viewDidAppear: invokes only once per appearance. All subsequent appearances invoke viewDidAppear: once.
The problem for me is that the first time I get to this view I end up with twice the number of subviews. I work around this problem by introducing a flag variable or some such, but I'd like to understand what is happening and how come I get two invocations in these circumstances.
You should never rely on -viewWillAppear:/-viewDidAppear: being called appropriately balanced with the disappear variants. While the system view controllers will do the best they can to always bracket the calls properly, I don't know if they ever guarantee it, and certainly when using custom view controllers you can find situations where these can be called multiple times.
In short, your -viewWillAppear:/-viewDidAppear: methods should be idempotent, meaning if -viewDidAppear: is called twice in a row on your controller, it should behave properly. If you want to load custom views, you may want to do that in -viewDidLoad instead and then simply put the on-screen (if they aren't already) in -viewDidAppear:.
You could also put a breakpoint in your -viewDidAppear: method to see why it's being called twice the first time it shows up.
maybe you invoke viewDidAppear in viewDidLoad (or some other stuff is going on there), since it's invoked only once during loading the view from the memory. It would match, that it's invoked two times only the first time.
This was not an iOS 5 bug, but a hidden behavior of addChildViewController:. I should file a radar for lack of documentation, I think
https://github.com/defagos/CoconutKit/issues/4
If you have a line like this in your AppDelegate
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
make sure you DON'T have a "Main nib file base name" property in your plist set to "Window.xib" or whatever your custom window nib is named. If you do, remove that row from your plist and make sure you something like
yourRootVC = [[UIViewController alloc] init];
[window setRootViewController:yourRootVC];
in your AppDelegate after instantiating your window. In most cases, you could then safely delete the Window.xib as well.
You definitely should provide more info.
Is this the root view controller?
Maybe you initiate the navigation controller with this root view controller and then push it to the navigation controller once again?
Another solution that may have been your underlying cause: Be sure you are not presenting any new view controllers from within your viewWillAppear: method.
I was calling:
[appDel.window.rootViewController presentViewController:login animated:YES completion:nil];
from within viewWillAppear and seeing my originating VC's viewDidAppear: method called twice successively with the same stack trace as you mention. And no intermediary call to viewDidDisappear:
Moving presentViewController: to the originating VC's viewDidAppear: method cleared up the double-call issue, and so now the flow is:
Original viewDidAppear: called
Call presentViewController here
Original viewDidDisappear: called
New view is presented and no longer gives me a warning about "unbalanced VC display"
Fixed with help from this answer: https://stackoverflow.com/a/13315360/1143123 while trying to resolve "Unbalanced calls to begin/end appearance transitions for ..."
it's such an annoying problem, you'd think it runs once but then I now found out about this which is causing mayhem... This applies to all 3 (ViewDidAppear, ViewDidLoad, and ViewWillAppear), I am getting this when integrating with a payment terminal; once it finish calling the API, the window is being re-loaded when it's already on-screen and all it's memory is still there (not retained).
I resolved it by doing the following to all the routines mentioned above, below is a sample to one of them:
BOOL viewDidLoadProcessed = false;
-(void)viewDidLoad:(BOOL)animated
{
if (!viewDidLoadProcessed)
{
viewDidLoadProcessed = YES;
.
.
.
... do stuff here...
.
.
}
}
Repeat the above for all the other two, this prevents it from running twice. This never occurred before Steve Jobs died !!!
Kind Regards
Heider Sati
Adding [super viewDidAppear:animated]; worked for me:
//Called twice
- (void)viewDidAppear:(BOOL)animated{
}
//Called once
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
}

dismissModalViewControllerAnimated: crashes in Simulator but not on phone

I'm doing the following:
[self.parentViewController dismissModalViewControllerAnimated:YES]
This code fails using the Simulator but works with no issues on the phone itself. The Simulator's console shows no erros. I used NSLog statements to pinpoint this line of code as the culprit. When running on the phone, however, the console(window>organizer) shows that the above code is executed and the application proceeds forward with no problem.
When running the code in debugger, the following statement appears at the bottom of the Xcode debug window:
GDB: Data Formatters temporarily unavailable, will re-try after a 'continue'. (Not safe to call dlopen at this time.)
Then a window dispalys stating: Loading 43672 stack frames. (that sounds bad)
In the debug window the following line appears numerous times:
[UIView(Hierarchy) _makeSubtreePerformSelector:withObject:withObject:copySublayers:]
Without getting too deep into my code, does anyone know about or have experience with this type of condition?
Thanks
Why you don't just call [self dismissModalViewControllerAnimated:YES]. It is quite enough to close you modal view controller.
I know, it isn't answer for your question, but maybe it helps to avoid your issue.
I think where you are calling this from is key but you don't say where this code is.
I suspect that dismissing your parentVC is causing this code to get executed again, which tries to dismiss the parent again... basically an infinite loop.
Thanks for the responses.
Aleksejs - I've tried your suggestion with no success. Thanks for making sure I've done the obvious first.
progrmr - I think you are probably correct - when and where I dismiss the modal view is the key and I'll look into how I'm doing this. I may need to re-architect how I'm handling my views.
This is frustrating because the issue does not happen on the iphone itself, only in the Simulator. And, I just confirmed that with the same MacBook Pro the error does not present itself in the Simulator when I'm working from home - the problem only occurs at my office. Strange, eh?
I'll keep digging and report my findings.
Thanks again.
Update - I didn't solve the problem but instead avoided it by re-structuring things. Before, in applicationDidFinishLaunching:, I presented a Login view controller as a modal view. I then need to display a EULA view controller so the user can agree to some legal stuff. I think my problem was that I was presenting the EULA view as a modal from the Login view (which is also modal). The order in which the modals were being presented/dismissed, I think, was the problem (as progrmr had suspected).
How I avoided the issue? I took the time to learn about the delegation pattern. Now, each modal view (Login and EULA) are presented within the app delegate class and I use delegates to callback when certain actions are taken on the modal views.
You shouldn't use self dismissModalViewControllerAnimated if self doesn't actually have a modalViewController. Just create a protocol that delegates the dismiss from the modal view controller back to the parent. when you push the modal view controller, assign the delegate, then when you want to dismiss it call [self.delegate dismissMe] which in turn calls [self dismissModalViewControllerAnimated:...] on the delegate (the parent).
[[Picker presentingViewController] dismissViewControllerAnimated:YES completion:nil];
Instead of
[[Picker parentViewControl] dismissModalViewControllerAnimated:YES];
and
[self presentViewController:picker animated:YES completion:nil];
Instead of
[self presentModalViewController:picker animated:YES];

iPhone UIViews sleeping/dying after being brought back into view

I need some help. This seems to be a common problem I am having when am adding and changing views in my coding. And I would love to learn what I am doing wrong.
Currently I am adding and removing views using the following calls from my view controller:
[startView removeFromSuperview];
[self addSubview:secondView];
and then doing the opposite again to go back.
[secondView removeFromSuperview];
[self addSubview:startView];
I am fine up to this point.
But the problem I have is that when I then decide to go back to 'startView" and call the first code that I have above for the second time.
My View loads but very little works.
None of my methods are called, there is no animation and the view is shown but it is "dead" or "asleep". And I have no idea why!
I am basically adding a view, removing it, then adding it again and everything breaks.
Can anyone give me a hand as to what might be happening? is it that ViewDidLoad doesn't fire the second time it's loaded? or something like that?
I would much appreciate it.
I may have figured it out So don't worry!
I had a flag hidden in my code somewhere that was stopping my methods from firing.
Sorry!

iPhone - Blank Screen when Switching VIews

I have an application that makes use of drill-down views, tabbars, etc. I'm also making use of the UIImagePicker, as well as Route-Me for mapping support. Normally, the application performs fine. However, I find that if I perform a lot of activities and then switch between views, I end up with a blank screen and my view is not drawn. My hunch is this is memory related, but how can I be sure? Has anyone encountered a similar situation? How did you go about correcting it? What can I look for? Thanks for any help you can give!
Steve
You're view is probably being unloaded in the background. If you have access to forums, here is a good thread:
https://devforums.apple.com/message/56191
Basically, you need to expect that while in another part of the application, iphone may unload a view which isn't active (see viewDidUnload method). When you switch to that view, it will then call viewDidLoad again.
I had this exact problem... In the method that handles my UIView switching, I checked for ([newViewController.view superview] == nil) which it was during a blank-out! So I went and re-initted it using [[NewViewController alloc] initWithNibName:#"NewView" bundle:nil]
Hope this helps!