xcode iPhone 应用程序中的异常:模态转换已在进行中
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3213734/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Exception in iPhone app : Modal transition is already in progress
提问by Diziet
I have what I believe is a fairly simple application at the moment based on a few tutorials cobbled together. I'm using XCode 3.2.3 in OSX 10.6.4. It started as a standard iPhone "Window Based Application". Using interface builder I have added a Tab Bar Controller using the O'Reilly video tutorial here:
我认为目前基于一些拼凑而成的教程是一个相当简单的应用程序。我在 OSX 10.6.4 中使用 XCode 3.2.3。它最初是一个标准的 iPhone“基于窗口的应用程序”。使用界面生成器,我在此处使用 O'Reilly 视频教程添加了一个 Tab Bar Controller:
http://broadcast.oreilly.com/2009/06/tab-bars-and-navigation-bars-t.html
http://broadcast.oreilly.com/2009/06/tab-bars-and-navigation-bars-t.html
In the first Tab I have a standard UIView with two buttons. Both call the same function to display a UIImagePickerController:
在第一个选项卡中,我有一个带有两个按钮的标准 UIView。两者都调用相同的函数来显示 UIImagePickerController:
-(IBAction) btnPhotoClicked:(id)sender {
UIImagePickerController *imagePicker = [[UIImagePickerController alloc] init];
imagePicker.delegate = self;
if((UIButton *)sender == btnChoosePhoto)
{
imagePicker.allowsEditing = YES;
imagePicker.sourceType = UIImagePickerControllerSourceTypeSavedPhotosAlbum;
} else {
imagePicker.sourceType = UIImagePickerControllerSourceTypeCamera;
}
[self presentModalViewController:imagePicker animated:YES];
[imagePicker release];
}
I am running the code inside an emulator so only ever click the button called Choose Photo. When the dialogue is released with a photo chosen this function runs:
我在模拟器中运行代码,所以只单击名为“选择照片”的按钮。当对话与选择的照片一起发布时,此功能将运行:
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
NSURL *mediaUrl;
mediaUrl = (NSURL *)[info valueForKey:UIImagePickerControllerMediaURL];
if (mediaUrl == nil)
{
imagePuzzle = (UIImage *) [info valueForKey:UIImagePickerControllerEditedImage];
if(imagePuzzle == nil)
{
//--- Original Image was selected ---
imagePuzzle = (UIImage *) [info valueForKey:UIImagePickerControllerOriginalImage];
}
else {
//--- Get the edited image ---
//--- If it was successful the above valueForKey:UIImagePickerControllerEditedImage
//--- would have assigned it already.
}
}
else {
//--- Muppet selected a video
}
// Animate the picker window going away
[picker dismissModalViewControllerAnimated:YES];
ImageViewController *imageViewController = [[ImageViewController alloc] init];
imageViewController.delegate = self;
[self presentModalViewController:imageViewController animated:YES];
[imageViewController release];
}
This is where my problem lies. I've tried many different hacks and iterations but the above code is the simplest to present the problem. When the imageViewController is displayed as a modal dialogue the following exception is thrown:
这就是我的问题所在。我尝试了许多不同的技巧和迭代,但上面的代码是最简单的解决问题的方法。当 imageViewController 显示为模态对话框时,抛出以下异常:
2010-07-09 15:29:29.667 Golovomka[15183:207] *** Terminating app due to uncaught
exception 'NSInternalInconsistencyException', reason: 'Attempting to begin a modal
transition from <NewViewController: 0x5915f80> to <ImageViewController: 0x594a350>
while a transition is already in progress. Wait for viewDidAppear/viewDidDisappear
to know the current transition has completed'
How do I cure this? I have tried delays and other tricks but do not really understand how I'm supposed to use viewDidAppear or viewDidDisappear to help me. Also of note is that a very basic application with one view loading the picker then displaying another view with the image in does not produce the error. Any help gratefully received.
我该如何治疗?我尝试过延迟和其他技巧,但并不真正理解我应该如何使用 viewDidAppear 或 viewDidDisappear 来帮助我。另外值得注意的是,一个非常基本的应用程序,其中一个视图加载选择器,然后显示另一个带有图像的视图,不会产生错误。感激地收到任何帮助。
回答by Eric
To address the specific issue described here, you could add the viewDidAppear method in your class:
要解决此处描述的特定问题,您可以在类中添加 viewDidAppear 方法:
-(void)viewDidAppear:(BOOL)animated
{
if (/*just visited ImagePicker*/)
{
ImageViewController *imageViewController = [[ImageViewController alloc] init];
imageViewController.delegate = self;
[self presentModalViewController:imageViewController animated:YES];
[imageViewController release];
}
}
Remove those lines from below your call:
从呼叫下方删除这些行:
[picker dismissModalViewControllerAnimated:YES];
So, whenever your class self
appears (is displayed), it will call viewDidAppear
... Since this most likely isn't reallywhat you want all the time, you could add some variables to set/clear that defines whether or not to immediately present the imageViewController
when self
is displayed. Something like "If coming from image picker, show the imageViewController, otherwise do nothing".
所以,当你的类self
出现(显示),它会调用viewDidAppear
......因为这最有可能是不是真的,你想要的东西的时候,你可能会有些变量添加到组/清除定义是否立即呈现imageViewController
什么时候self
显示。类似于“如果来自图像选择器,则显示 imageViewController,否则什么都不做”。
That said, imho, pushing modal views is should generally be done in response to a user action and I would maybe rethink the user experience here - e.g. add a subview instead of pushing a modal view which you could do where your currently have the code - but if you're just playing around with some tutorials that should solve the NSInternalInconsistencyException. :) Cheers!
也就是说,恕我直言,推送模态视图通常应该是响应用户操作而完成的,我可能会重新考虑这里的用户体验 - 例如添加一个子视图而不是推送一个模态视图,您可以在当前拥有代码的地方执行该操作 -但如果你只是在玩一些应该解决 NSInternalInconsistencyException 的教程。:) 干杯!
回答by Luong Huy Duc
In iOS 5.0 and above you can use
在 iOS 5.0 及以上你可以使用
[self dismissViewControllerAnimated:YES completion:^{
//present another modal view controller here
}];
回答by Dirk Puis
I ran into this issue quite a few times. I recently started using this simple fix:
我多次遇到这个问题。我最近开始使用这个简单的修复:
When I am going to present a new modal view controller immediately after dismissing another modal view controller, I simply dismiss the first one with argument NO in dismissModalViewControllerAnimated:
.
当我要在关闭另一个模态视图控制器后立即呈现一个新的模态视图控制器时,我只是用参数 NO in 关闭第一个dismissModalViewControllerAnimated:
。
Since the second view is presented with an animation, you hardly notice that the first one goes away fast. And you never get the transitions conflict.
由于第二个视图带有动画,您几乎不会注意到第一个视图消失得很快。而且您永远不会遇到转换冲突。
回答by Bushra Shahid
I was having the same problem when i wanted to present an MFMailComposeViewController immediately after dismissing the UIImagePickerController. Heres what i did:
当我想在关闭 UIImagePickerController 后立即呈现 MFMailComposeViewController 时,我遇到了同样的问题。这是我所做的:
I removed the
[imagePicker release];
statement from where i was presenting the image picker and put it in didFinishPickingMedia callback.I used
[self performSelector:@selector(presentMailComposer:) withObject:image afterDelay:1.0f];
我
[imagePicker release];
从我展示图像选择器的地方删除了该语句,并将其放入 didFinishPickingMedia 回调中。我用了
[self performSelector:@selector(presentMailComposer:) withObject:image afterDelay:1.0f];
Here's my code: Displaying Image Picker
这是我的代码:显示图像选择器
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
NSArray *media = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
if([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) {
NSArray *media = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
if ([media containsObject:(NSString*)kUTTypeImage] == YES) {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
[picker setMediaTypes:[NSArray arrayWithObject:(NSString *)kUTTypeImage]];
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
picker.delegate = self;
[self presentModalViewController:picker animated:YES];
//[picker release];
}
}
else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Unavailable!"
message:@"Could not open the Photo Library."
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
if ([media containsObject:(NSString*)kUTTypeImage] == YES) {
UIImagePickerController *picker = [[UIImagePickerController alloc] init];
[picker setMediaTypes:[NSArray arrayWithObject:(NSString *)kUTTypeImage]];
picker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
picker.delegate = self;
[self presentModalViewController:picker animated:YES];
//[picker release];
}
}
else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Unavailable!"
message:@"Could not open the Photo Library."
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
Image Picker Delegate Callback - didFinishPickingMedia
图像选取器委托回调 - didFinishPickingMedia
NSString *mediaType = [info valueForKey:UIImagePickerControllerMediaType];
NSString *mediaType = [info valueForKey:UIImagePickerControllerMediaType];
if([mediaType isEqualToString:(NSString*)kUTTypeImage]) {
UIImage *photoTaken = [info objectForKey:@"UIImagePickerControllerOriginalImage"];
//Save Photo to library only if it wasnt already saved i.e. its just been taken
if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
UIImageWriteToSavedPhotosAlbum(photoTaken, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}
//Pull up MFMailComposeView Controller
[self performSelector:@selector(composeMailWithPhoto:) withObject:photoTaken afterDelay:1.0f];
}
[picker dismissModalViewControllerAnimated:YES];
[picker release];
if([mediaType isEqualToString:(NSString*)kUTTypeImage]) {
UIImage *photoTaken = [info objectForKey:@"UIImagePickerControllerOriginalImage"];
//Save Photo to library only if it wasnt already saved i.e. its just been taken
if (picker.sourceType == UIImagePickerControllerSourceTypeCamera) {
UIImageWriteToSavedPhotosAlbum(photoTaken, self, @selector(image:didFinishSavingWithError:contextInfo:), nil);
}
//Pull up MFMailComposeView Controller
[self performSelector:@selector(composeMailWithPhoto:) withObject:photoTaken afterDelay:1.0f];
}
[picker dismissModalViewControllerAnimated:YES];
[picker release];
Display Mail Composer View
显示邮件编辑器视图
if ([MFMailComposeViewController canSendMail]) {
if ([MFMailComposeViewController canSendMail]) {
MFMailComposeViewController *mailPicker = [[MFMailComposeViewController alloc] init];
mailPicker.mailComposeDelegate = self;
// Fill out the email fields and Attach photograph to mail
static NSString *imageType = @"image/jpeg";
NSString *imageName = [NSString stringWithString:@"MyCoffeeCup.jpg"];
NSData *imageData = UIImageJPEGRepresentation(image, 1.0);
[mailPicker addAttachmentData:imageData mimeType:imageType fileName:imageName];
[mailPicker setToRecipients:[NSArray arrayWithObject:@"[email protected]"]];
[self presentModalViewController:mailPicker animated:YES];
//[self.navigationController pushViewController:mailPicker animated:YES];
[mailPicker release];
}
else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Unavailable!"
message:@"This device cannot send emails."
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
MFMailComposeViewController *mailPicker = [[MFMailComposeViewController alloc] init];
mailPicker.mailComposeDelegate = self;
// Fill out the email fields and Attach photograph to mail
static NSString *imageType = @"image/jpeg";
NSString *imageName = [NSString stringWithString:@"MyCoffeeCup.jpg"];
NSData *imageData = UIImageJPEGRepresentation(image, 1.0);
[mailPicker addAttachmentData:imageData mimeType:imageType fileName:imageName];
[mailPicker setToRecipients:[NSArray arrayWithObject:@"[email protected]"]];
[self presentModalViewController:mailPicker animated:YES];
//[self.navigationController pushViewController:mailPicker animated:YES];
[mailPicker release];
}
else {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Unavailable!"
message:@"This device cannot send emails."
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}