If I dismiss the the modal VC and present it (or another one) again in less than a certain amount of time, it does not appear.
Am I missing something?
Yes, you can't do that. I'm assuming what you did is something like this:
[self dismissModalViewControllerAnimated:YES];
[self presentModalViewController:myNewController animated:YES];
This doesn't work. I don't know exactly why, but it is related to the animations I believe. Your options are to either dismiss the first one without animation, or else wait to present the new one in viewDidAppear of the parent, (or possibly viewDidDisappear for the previous modal view, not sure if that works though).
You cant dismiss two modal view controllers right after another, aside from what the other poster suggested, you can wait a small amount of time before dismissing the other modal view, for example
[self performSelector:#selector(method) withObject:nil afterDelay:.5];
where the method called just dismisses your other modal view.
The snippet of code performs the selector after .5 seconds and can be used when having animation timing problems like the one you describe, to seperate the call times in order for them to execute properly.
Related
i have a tough one for you today. I have two tableViews in my app the first is on the first page. There are two other pages the user drills down to get to the second table view. After i leave the first table view, i can press the back buttons to get back perfectly until i reach the second table view. As soon as i drill down to the second table view and then try to return to the first via pressing the back buttons. As soon as i get to the last back button to return to the first table view, the app crashes. The code for the back buttons is simply:
- (IBAction)goBack:(id)sender {
[self dismissModalViewControllerAnimated:YES];
}
Any Help Would be greatly appreciated!! Thanks everyone!! :D
Whenever I create a modal view controller from a XIB, the automatic #property generator duplicates things in the Dealloc method, thus throwing an EXC_BAD_ACCESS when the view is dismissed. Make sure you aren't releasing something twice.
Sounds like your are releasing something too early. Open you app in instruments (command + i) and run a zombie test.
As soon as you see zombie has been messaged expand the right panel and have a look at the user code (your code) blocks. Indicated by the back person icon.
Double click that and it will indicate what it was trying to access that had already been released.
Are your tableviews being displayed in a modal window? If not, why are you calling [self dismissModalViewControllerAnimated:YES]? Shouldn't you be calling [[self navigationController] popViewControllerAnimated:YES]?
If you're using a UINavigationController, the back button functionality should be provided automatically.
if you are using [[self navigationController] popViewControllerAnimated:YES] to
then for back you write as mentioned below:
(IBAction)goBack:(id)sender {
// Tell the controller to go back
[self.navigationController popViewControllerAnimated:YES];
}
if you are using [self presentmodalviewcontroller: animated:]
then only [self dismissModalViewControllerAnimated:YES] will work
you try this [[self navigationController] popViewControllerAnimated:YES]
I have the following code
- (void) viewWillAppear:(BOOL)animated
{
NSLog(#"dismiss view");
[self dismissModalViewControllerAnimated:YES];
}
This prints dismiss view but won't execute the view dismissal code.
Can a view be dismissed in code without a trigger from an IBAction?
Why wouldn't this be executing?
You would probably have better luck putting the code into viewDidAppear rather than viewWillAppear. The latter tends to be called right at the start of any animation such as a modal beginning to slide off the screen; the former tends to be called when that animation has completely finished. Note that even if this strategy works, you may end up with a weird effect whereby two modals are seen to slide off, one after the other; I presume you just want one sliding off effect.
What happens if you dismiss the "lower down" modal dialog (the one first pushed), and don't bother dismissing the one that is topmost?
Also consider paying attention to the animated argument when dismissing your modal view controller. Different combinations of animated or not can have different effects when you have problems like yours.
If you post a more complete code sample we can give a better answer!
try with a little delay on the second dismiss.
- (void) viewWillAppear:(BOOL)animated
{
NSLog(#"dismiss view");
[self performSelector:#selector(delayedDismiss) withObject:nil afterDelay:0.5];
}
-(void)delayedDismiss{
[self dismissModalViewControllerAnimated:YES];
}
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];
}
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];
So in my app delegate I add a call add the myViewController.view to the main window:
1. [window addSubview:myViewController.view];
In myViewController I do the following code in the viewDidAppear method:
2. [self presentModalViewController: yourViewController animated: YES];
In my yourViewController class I do the following to try and go back to the main window
3. [self dismissModalViewControllerAnimated:YES];
My main windows view appears with buttons in all, but the buttons won't react to any click or anything. It's like there is something over them that I can't see.
Also, the main windows button works before this process but doesn't after the process.
Any help would be appreciated.
If the dismiss method call is in the modal view controller (not the parent that presents it), then you actually want to call [self.parentController dismissModalViewControllerAnimated:YES];
There are a number of reasons why things might not be responding to your touches. Here are two that have happened to me:
The frame of the view you want to touch is too small. UIViews can draw outside of their frames, so it might look ok, but not respond if the touch is technically outside of the frame -- you also have to check that all the superview's up the hierarchy also have a large enough frame.
If anything in your view is a UIImageView or child thereof, it won't respond to user touches because UIImageView has userInteractionEnabled set to NO by default. You can fix this just by setting myImageView.userInteractionEnabled = YES;
Edit: Oli pointed out in the comments that dismissModalViewControllerAnimated: should work if called on either self.parentController or simply self, since that method is smart enough to call the parent if needed, according to the docs. The docs also make it sound like this might behave differently if you have multiple model views open at once, though, so I would still consider it cleaner code to call the method on self.parentController directly.