presentModalViewController崩溃我的应用程序

时间:2009-07-04 20:53:02

标签: iphone uiviewcontroller modal-dialog mfmailcomposeviewcontroller

这是最简单的事情之一,我知道。但是我几天来一直在反对这个问题。我过去已经做了很多次,但出于某种原因试图提出模态视图控制器只是将应用程序崩溃到黑屏。控制台或其他任何内容都没有报告。我希望有人可能遇到这个问题并提出一些建议。

此代码从UIViewController类调用:

MFMailComposeViewController *controller = [[MFMailComposeViewController alloc] init];
controller.mailComposeDelegate = self;
[controller setSubject:@"test subject"];
[controller setMessageBody:@"this is the message body" isHTML:NO];
[self presentModalViewController:controller animated:YES];

4 个答案:

答案 0 :(得分:3)

正如安德鲁在评论中指出的那样,你检查

+[MFMailComposeViewController canSendMail]

在尝试推送视图控制器之前?如果此方法返回NO(在模拟器上运行时也可能是这种情况,但我不确定),MFMailComposeViewController的行为没有明确定义。来自文档:

  

在使用本课程之前,您必须   总是检查当前是否有   设备配置为发送电子邮件   全部使用canSendMail方法。如果   未设置用户的设备   发送电子邮件,您可以通知   用户或只是禁用电子邮件   在您的应用程序中调度功能。   你不应该试图使用它   接口如果是canSendMail方法   返回NO。

您是否尝试过另一个视图控制器?这也会让你的应用程序崩溃吗?

答案 1 :(得分:3)

在尝试显示MFMailComposeViewController之前,您是否正在显示另一个模态视图控制器?我遇到了同样的问题并找到了解决方法:

- (void)peopleMultiPickerNavigationController:(PeopleMultiPickerNavigationController *)peoplePicker 
                                didSelectContacts:(NSArray *)contacts {

[self dismissModalViewControllerAnimated:YES];

// some more code here

[self performSelector:@selector(sendEmail) withObject:nil afterDelay:0.45]; // this works only if delay > ~0.4!
// [self sendEmail]; // this won't work

// some more code here

}

- (void) sendEmail {
  Class mailClass = (NSClassFromString(@"MFMailComposeViewController"));
  if (mailClass != nil) {
    // We must always check whether the current device is configured for sending emails
    if ([mailClass canSendMail]) {
      [self displayComposerSheet:emails];
    } else {
      [self launchMailAppOnDevice:emails];
    }
  } else {
    [self launchMailAppOnDevice:emails];
  } 
}

我知道这是一个丑陋的解决方法,但我没有找到更好的方法:(

答案 2 :(得分:2)

我不知道这是多么相关,但是在从另一个模态视图控制器返回到我的主视图控制器后尝试呈现MFMailComposeViewController时遇到了可怕的问题。它只是行不通。我试图在启动邮件控制器之前解雇这个其他模态视图控制器,并发现我的解决方案是不调用:

[self dismissModalViewControllerAnimated:YES];

但请致电:

[self dismissModalViewControllerAnimated:NO];

然后继续呈现邮件视图控制器。

这一改变在我的案例中完全不同。我怀疑这与sgosha所遇到的问题有关。只需关闭动画,而不是延迟(这可能只是等到动画完成)。看起来框架中的错误对我来说。

我应该进一步解释。我的主视图控制器上有一个共享按钮,它以模态方式弹出一个表视图,以允许用户选择他们想要共享的内容。从这里开始,如果他们点击电子邮件,他们会得到一张UIActionSheet,让他们进一步决定他们希望将哪些文件附加到他们的电子邮件中。

混合中的UIActionSheet可能会导致问题。模态视图控制器的实际解雇发生在我的主视图控制器中的委托方法中,正是这个主视图控制器在解除模态表视图控制器后尝试启动邮件视图控制器。

答案 3 :(得分:2)

是的!我做到了!我无法相信,但我解决了这个问题!这与以下内容有关:

从(及以上)其他一些打开的模态控制器

打开MFMailComposeViewController作为模态

不幸的是,我不得不承认,再次,在像Devil-iPhones5这样昂贵的时代,Apple仍然会让开发人员使用旧的,错误的,不方便的代码和组件!最好的例子是MFMailComposeViewController。


但是现在让我们关注更愉快的事情。

我们有什么:

  • 这个问题出现在带有iOS 5.1的iPhone和使用iOS 6的模拟器上。
  • 核心问题是当您尝试从另一个模态控制器打开电子邮件控制器作为模态控制器时。
  • [MFMailComposeViewController canSendMail ]对我来说绝对没有效果 - 它无法以两种方式工作(无论是否有电子邮件功能都崩溃了。)
  • [self dismissModalViewControllerAnimated: NO / YES ] 没有改变一般意义 - 它以两种方式崩溃,但行为略有不同。
  • 我尝试使用标准方法 mailComposeDelegate (例如'.mailComposeDelegate = self')。
  • 我在同一个应用程序中调用了两个方面的电子邮件发送控制器:普通(第一级)控制器以及模态(第二级)控制器。
  • 应用程序并不总是崩溃 - 有时控制器无法自行解除(按钮“取消”和“发送”处于活动状态,但未处理任何操作)。依赖于条件(父母是谁打开控制器,是动画还是没有出现等)。
  • 如果添加了电子邮件接收者,也没有区别。

所以,我被杀的5个工作小时发现的是,似乎代表在某种程度上是“释放”了。我可以假设,如果你打开电子邮件控制器作为modal而不是其他模态控制器,那个(以前的模态)控制器正在被垃圾收集器或其他方式清理,那样代理也被清理了(我没有希望)再多花几个小时进行详细的挖掘,所以我把它留给了Apple的良心。)

无论如何,用两个词来说,我的解决方案是

将委托对象保存在“强”引用的某处。

在我的情况下,该委托的所有者是主视图控制器类(在我的情况下总是可用的,因为大多数应用程序逻辑正在使用它)。那也可以是AppDelegate实例。

看起来像是:

@interface SharingTools : NSObject <MFMailComposeViewControllerDelegate>

@property UIViewController* currentParentController;

...

-(void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error
{
    if (error)
    {
        ...
    }
    else
    {
        // I pass it somewhere before calling the email controller dialog opener method,
        // because it's different in case we open the email sender 
        // from first-level controller or second- (the modal one)
        [currentParentController dismissViewControllerAnimated:YES completion:^{

            if (_onResult) {
                    ((void(^)(bool))_onResult)(result == MFMailComposeResultSent);
            }
        }];
    }

    // and of course clearing all the references etc here
    currentParentController.mailComposeDelegate = nil;
    currentParentController = nil;
}

-(void)sendEmail //... params here 
                 // (possibly, including to store also currentParentController)
{
    currentParentController = ... ;
    [currentParentController presentViewController:
                  newlyCreatedEmailController animated:YES completion:nil];
}
@end

@interface MyMainViewController : UIViewController

@property SharingTools* sharing; // initialize somewhere (on viewDidLoad, for instance)

...

-(void)showSettings
{
    ...
    [self presentModalViewController:settingsController animated:YES];
}
@end

@interface SettingsViewController : UIViewController

...

-(void)sendEmailSupport
{
    // again, this is up to you where and how to have either reference 
    // to main controller (or any other owner of the delegate object)
    // or sharing directly
    [myMainViewControllerInstance.sharing sendEmail: ... parentController:self];

}
@end

坦率地说,代码有点乱,但这只是一般的想法。 我希望,你会更好地管理自己。

祝你好运,上帝保佑微软! ^^