31

I'm trying to display a modal view straight after another view has been presented modally (the second is a loading view that appears).

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    // Show load
    LoadViewController *loader = [[LoadViewController alloc] init];
    [self presentModalViewController: loader animated:NO];
    [loader release];
}

But when I do this I get a "Program received signal: "EXC_BAD_ACCESS"." error.

The stack trace is:

0  0x30b43234 in -[UIWindowController transitionViewDidComplete:fromView:toView:]
1  0x3095828e in -[UITransitionView notifyDidCompleteTransition:]
2  0x3091af0d in -[UIViewAnimationState sendDelegateAnimationDidStop:finished:]
3  0x3091ad7c in -[UIViewAnimationState animationDidStop:finished:]
4  0x0051e331 in run_animation_callbacks
5  0x0051e109 in CA::timer_callback
6  0x302454a0 in CFRunLoopRunSpecific
7  0x30244628 in CFRunLoopRunInMode
8  0x32044c31 in GSEventRunModal
9  0x32044cf6 in GSEventRun
10 0x309021ee in UIApplicationMain
11 0x00002154 in main at main.m:14

Any ideas? I'm totally stumped! The loading view is empty so there's definitely nothing going on in there that's causing the error. Is it something to do with launching 2 views modally in the same event loop or something?

Thanks,

Mike

Edit: Very strange... I have modified it slightly so that the loading view is shown after a tiny delay, and this works fine! So it appears to be something within the same event loop!

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    // Show load
    [self performSelector:@selector(doit) withObject:nil afterDelay:0.1];
}

- (void)doit {
    [self presentModalViewController:loader animated:YES];  
}
Michael Waterfall
  • 20,497
  • 27
  • 111
  • 168
  • Just where is the EXC_BAD_ACCESS coming from? You give us a stack trace here, but I'm not sure that the error is happening in this chunk of code. Can you edit the post to give us the full log with traces of where all the threads were? – Gordon Seidoh Worley Sep 11 '09 at 16:54
  • I'm not sure where it's coming from. That's the only trace I have, it would appear the bad access isn't coming from my code, so it's something internally accessing something, so I can't pinpoint it! I've ensured everything is retained so I've got no idea what's going on! – Michael Waterfall Sep 11 '09 at 17:20
  • Try putting `loader` in the autorelease pool. I think that loader is disappearing too soon, probably because the current view controller has to get out of the way for the new view and view controller. Other ideas: use the debugger and watch loader. If it is what's causing the trouble, you'll discover it that way. If not, keep poking around in the debugger and you might figure it out. – Gordon Seidoh Worley Sep 11 '09 at 17:59
  • Okay I'll give it a try. How can I watch the loader with the debugger? By using breakpoints? Or is there another way to monitor things other than that? Would be interested to know if there's other ways to debug! – Michael Waterfall Sep 11 '09 at 18:04
  • I think the reason for the loop is that new view controller you are loading has a view did appear method by default and it has [super viewdidappear animated]; which means it will call back to your main view controller's viewDidAppear again, like that it will go on a loop – NSGodMode Mar 26 '15 at 21:38

16 Answers16

30

I have modified it slightly so that the loading view is shown after a tiny delay, and this works fine! So it appears to be something within the same event loop!

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];
    // Show load
    [self performSelector:@selector(doit) withObject:nil afterDelay:0.1];
}

- (void)doit {
    [self presentModalViewController:loader animated:YES];  
}
Michael Waterfall
  • 20,497
  • 27
  • 111
  • 168
5

I believe I reproduced the same error in iOS 4. In my application, the crash occurred consistently when attempting to show a second modal view immediately after showing a first modal view. I struggled for a few hours going insane.

After reading the posts in this thread, I tried to create a simple reproducible example using the Tab Bar Application template. I was able to use the UIImagePickerController to show the first modal view after responding to a button click in "FirstViewController.m". When I tried to show the UIImagePickerController again (after handling the imagePickerControllerDidCancel message), the application crashed with the same error.

On the device, there was simply no clue what was going on. However, when I ran the code on the Simulator, I was lucky enough to get this message on the console:

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Attempting to begin a modal transition from to while a transition is already in progress. Wait for viewDidAppear/viewDidDisappear to know the current transition has completed'

So it seems that my only choice is to follow the advice of the error message and simply wait until viewDidAppear (using a flag to indicate I'm in this special mode) and then load the second modal view.

Here's the full stack trace for completeness:

** Call stack at first throw:
(
 0   CoreFoundation                      0x0238c919 __exceptionPreprocess + 185
 1   libobjc.A.dylib                     0x024da5de objc_exception_throw + 47
 2   CoreFoundation                      0x02345078 +[NSException raise:format:arguments:] + 136
 3   Foundation                          0x000ab8cf -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 116
 4   UIKit                               0x00544317 -[UIWindowController transition:fromViewController:toViewController:target:didEndSelector:] + 212
 5   UIKit                               0x0035c769 -[UIViewController presentModalViewController:withTransition:] + 2937
 6   TestTempDelete                      0x000021cf -[FirstViewController showImagePicker] + 167
 7   Foundation                          0x0002fcea __NSFireDelayedPerform + 441
 8   CoreFoundation                      0x0236dd43 __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ + 19
 9   CoreFoundation                      0x0236f384 __CFRunLoopDoTimer + 1364
 10  CoreFoundation                      0x022cbd09 __CFRunLoopRun + 1817
 11  CoreFoundation                      0x022cb280 CFRunLoopRunSpecific + 208
 12  CoreFoundation                      0x022cb1a1 CFRunLoopRunInMode + 97
 13  GraphicsServices                    0x02bf12c8 GSEventRunModal + 217
 14  GraphicsServices                    0x02bf138d GSEventRun + 115
 15  UIKit                               0x002beb58 UIApplicationMain + 1160
 16  TestTempDelete                      0x00001eb4 main + 102
 17  TestTempDelete                      0x00001e45 start + 53

Hope this helps.

bdesham
  • 15,430
  • 13
  • 79
  • 123
Daniel
  • 8,794
  • 4
  • 48
  • 71
4

**Like was said earlier, use isIgnoringInteractionEvents

//Check if the app is ignoring interatctions, if so, add a delay for 1 sec
if([[UIApplication sharedApplication] isIgnoringInteractionEvents]==TRUE) {
        [currentViewController performSelector:@selector(presentModalViewController:animated:) withObject:screen afterDelay:1];
    } else {
        [currentViewController presentModalViewController:screen animated:YES];
    }
Robert Harvey
  • 178,213
  • 47
  • 333
  • 501
user353877
  • 1,211
  • 1
  • 15
  • 21
3

It's possible if you're getting this after clicking a button which was linked to your code in Interface Builder, that you've got two actions linked to one button (maybe if you had a modal view linked to a button, then duplicated the button and linked another modal view). This will try to fire them both off and therefore it'll fail with that message.

Simon
  • 31
  • 1
3

I encountered the same exception

Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Attempting to begin a modal transition from to while a transition is already in progress. Wait for viewDidAppear/viewDidDisappear to know the current transition has completed'

As suggested earlier I tried to delay presenting a modal transition, but that did not really help. I then found that I had multiple IBActions connected to my button's TouchUpInside event!!!. In my case two IBActions would start: presenting a people picker modally and presenting an image picker modally. This explains the error message. Check if you have multiple IBActions connected!

Eddy
  • 31
  • 1
1

Your problem is most likely in the method that inits and presents the method that viewDidAppear is in, or in the init/viewDidLoad/viewWillAppear method of LoadViewController.

Set some break points and follow until crash...

Jordan
  • 21,746
  • 10
  • 51
  • 63
  • Those methods are pretty much empty. All I do is change background colour on viewDidLoad:. The application executes these lines fine, the crash doesn't occur in my code, it's crashing when other things are being performed later on in the event loop. – Michael Waterfall Sep 11 '09 at 18:20
1

I think this issue has something to do with a problem that I also encountered. It is very easy to reproduce:

Create new XCode Project "Utility Application". In the FlipsideViewController.m you just insert the following method:

- (void)viewDidAppear:(BOOL)animated {
  [super viewDidAppear: animated];
  [self showInfo];
}

If you do this, start the application, then the flipside-view will be activated right away. As soon as you press the "Done" Button on the flipside-view, you will get back to the Mainview which fires viewDidAppear again and goes right back to the flipside- view. As soon as the flipside-view is displayed, the application stops - no memory deallocators are called - it is just like you have pressed the home-button.

When I was using some additional properties in those views, I also got the exception, so I stripped down the code to the minimum amount...

I really have no clue, what this problem really is...

Best regards, Tobias

Maulik
  • 19,348
  • 14
  • 82
  • 137
Tobias
  • 19
  • 1
1

I had a similar error when clicking on a UIButton to open a Modal View. I changed the UIButton's listener from UIControlEventAllEvents to UIControlEventTouchUpInside. Basically, it was firing the Modal View on Touch Down Inside and then again on Touch Up Inside.

Chris
  • 5,485
  • 15
  • 68
  • 130
  • Good answer. To generalize it: Watch for code that opens a Modal View and make sure it is only called once. Doesn't have to be from a button click. – Tal Bereznitskey Nov 08 '11 at 15:31
1

I had the same problem due to mismatch between names in

HelpViewController *controller = [[HelpViewController alloc] initWithNibName:@"HelpView" bundle:nil];

and the name of the actual .xib file.

Alexey Podlasov
  • 993
  • 10
  • 18
0

It really depends on what the support routines for viewDidAppear are doing. For example, if presentModalViewController:animated: does not retain loader the crash may be due to the UIWindowController trying to speak about loader which has since been released (at the end of the routine you posted).

fbrereto
  • 35,429
  • 19
  • 126
  • 178
  • Thanks for your comment. I've tried storing it in an instance variable so it is definitely retained and I'm still getting the error. – Michael Waterfall Sep 11 '09 at 17:19
  • 1
    There are two views in play here -- the one coming in and the one going out -- are you retaining both until the transition is complete? Maybe there's an issue with keeping both views alive until then. – fbrereto Sep 11 '09 at 17:51
0

I had a similar problem while using the same technique as you to implement a loading view. It would crash when the loading view was dismissed at the end of the load. In my case, the problem came from the fact that as soon as the loading view was dismissed viewDidAppear was called again and tried to present the loading view again, which presumably triggered the crash. I fixed it simply by checking if the loading view had been presented before:

- (void)viewDidAppear:(BOOL)animated {
    [super viewDidAppear:animated];

    if(needDisplayLoader)
        [self presentModalViewController: loader animated:NO];
}

Then I set needDisplayLoader to NO before dismissing the Loader view

Hope this helps...

Rom
  • 1
0

I ran into this issue just now, and corrected it using the selector:afterDelay suggestion above. Just to add, I compiled (without the fix) under iPhone OS 4.0 beta, and NO CRASH! So, the bug in XCode appears to have been fixed in the next gen. Not that this does any of us any good today, but, just so you all know, it truly was a bug in Xcode and not necessarily anything we were doing wrong in our coding styles.

pulseft
  • 61
  • 2
0

I think the reason for the loop is that new view controller you are loading has a viewDidAppear method by default and it has

[super viewDidAppear animated];

which means it will call back to your main view controller's viewDidAppear again, like that it will go on a loop

in Viewcontroller you are presenting have a method like this, without super viewdidapper:

-(void)viewDidAppear:(BOOL)animated{
    //[super viewDidAppear:animated]; no super

}
NSGodMode
  • 599
  • 1
  • 6
  • 16
0

Had exact same problem. Solved it with the above suggested...

[self performSelector:@selector(doit) withObject:nil afterDelay:0.5];

Had to use a 0.5 sec delay. Possibly because I was performing presentModalViewController directly after a UIPickerViewController modal.

0

I just had this problem and it turned out that my problem was because I was dealloc my protocol delegate.

NixonsBack
  • 390
  • 2
  • 15
-2

EXC_BAD_ACCESS is a memory error. You're probably trying to use an object that has already been released/deallocated. This answer gives some tips for debugging these issues:

Debugging EXC_BAD_ACCESS

Community
  • 1
  • 1
pix0r
  • 31,139
  • 18
  • 86
  • 102