我对Simulator中的Swift(iOS8)中的MFMailComposeViewController有误解

Ale*_*mov 55 ios uidocumentinteraction mfmailcomposer uiactivityviewcontroller

我创建了一个csv文件并尝试通过电子邮件发送它.显示发送邮件的窗口,但不填充电子邮件正文,也没有附加文件.应用程序挂起此屏幕:

prntscr.com/4ikwwm

按钮"取消"不起作用.在控制台中出现几秒钟后:

viewServiceDidTerminateWithError: Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "The operation couldn’t be completed. (_UIViewServiceInterfaceErrorDomain error 3.)" UserInfo=0x7f8409f29b50 {Message=Service Connection Interrupted}

<MFMailComposeRemoteViewController: 0x7f8409c89470> timed out waiting for fence barrier from com.apple.MailCompositionService
Run Code Online (Sandbox Code Playgroud)

有我的代码:

func actionSheet(actionSheet: UIActionSheet!, clickedButtonAtIndex buttonIndex: Int) {
    if buttonIndex == 0 {
        println("Export!")

        var csvString = NSMutableString()
        csvString.appendString("Date;Time;Systolic;Diastolic;Pulse")

        for tempValue in results {     //result define outside this function

            var tempDateTime = NSDate()
            tempDateTime = tempValue.datePress
            var dateFormatter = NSDateFormatter()
            dateFormatter.dateFormat = "dd-MM-yyyy"
            var tempDate = dateFormatter.stringFromDate(tempDateTime)
            dateFormatter.dateFormat = "HH:mm:ss"
            var tempTime = dateFormatter.stringFromDate(tempDateTime)

            csvString.appendString("\n\(tempDate);\(tempTime);\(tempValue.sisPress);\(tempValue.diaPress);\(tempValue.hbPress)")
        }

        let fileManager = (NSFileManager.defaultManager())
        let directorys : [String]? = NSSearchPathForDirectoriesInDomains(NSSearchPathDirectory.DocumentDirectory,NSSearchPathDomainMask.AllDomainsMask, true) as? [String]

        if ((directorys) != nil) {

            let directories:[String] = directorys!;
            let dictionary = directories[0];
            let plistfile = "bpmonitor.csv"
            let plistpath = dictionary.stringByAppendingPathComponent(plistfile);

            println("\(plistpath)")

            csvString.writeToFile(plistpath, atomically: true, encoding: NSUTF8StringEncoding, error: nil)

            var testData: NSData = NSData(contentsOfFile: plistpath)

            var myMail: MFMailComposeViewController = MFMailComposeViewController()

            if(MFMailComposeViewController.canSendMail()){

                myMail = MFMailComposeViewController()
                myMail.mailComposeDelegate = self

                // set the subject
                myMail.setSubject("My report")

                //Add some text to the message body
                var sentfrom = "Mail sent from BPMonitor"
                myMail.setMessageBody(sentfrom, isHTML: true)

                myMail.addAttachmentData(testData, mimeType: "text/csv", fileName: "bpmonitor.csv")

                //Display the view controller
                self.presentViewController(myMail, animated: true, completion: nil)
            }
            else {
                var alert = UIAlertController(title: "Alert", message: "Your device cannot send emails", preferredStyle: UIAlertControllerStyle.Alert)
                alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Default, handler: nil))
                self.presentViewController(alert, animated: true, completion: nil)


            }
        }
        else {
            println("File system error!")
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

尝试使用UIActivityViewController以下方式发送邮件:

let fileURL: NSURL = NSURL(fileURLWithPath: plistpath)
let actViewController = UIActivityViewController(activityItems: [fileURL], applicationActivities: nil)
self.presentViewController(actViewController, animated: true, completion: nil)
Run Code Online (Sandbox Code Playgroud)

看到大致相同的屏幕发送电子邮件,一段时间后返回上一个屏幕.在控制台中,现在出现另一个错误:

viewServiceDidTerminateWithError: Error Domain=_UIViewServiceInterfaceErrorDomain Code=3 "The operation couldn’t be completed. (_UIViewServiceInterfaceErrorDomain error 3.)" UserInfo=0x7faab3296ad0 {Message=Service Connection Interrupted}
Errors encountered while discovering extensions: Error Domain=PlugInKit Code=13 "query cancelled" UserInfo=0x7faab3005890 {NSLocalizedDescription=query cancelled}
<MFMailComposeRemoteViewController: 0x7faab3147dc0> timed out waiting for fence barrier from com.apple.MailCompositionService
Run Code Online (Sandbox Code Playgroud)

有一些事情PlugInKit.

尝试UIActivityViewController使用UIDocumentInteractionController:

let docController = UIDocumentInteractionController(URL: fileURL)
docController.delegate = self
docController.presentPreviewAnimated(true)
...

func documentInteractionControllerViewControllerForPreview(controller: UIDocumentInteractionController!) -> UIViewController! {
    return self
}
Run Code Online (Sandbox Code Playgroud)

我看到这个屏幕的内容是一个CSV文件:http://prntscr.com/4ilgax我在右上角按下按钮导出并看到这个屏幕http://prntscr.com/4ilguk我在哪里选择MAIL并且几秒钟我看到http://prntscr.com/4ilh2h然后返回显示文件的内容!在控制台中使用时的消息相同UIActivityViewController.

Fat*_*tie 117

**重要 - 请勿使用此模拟器.**

即使在2016年,模拟器也很不支持从应用程序发送邮件.

实际上,模拟器根本就没有邮件客户端.

但!请在底部看到消息!


亨利给出了完整的答案.你必须

- 在早期阶段分配和启动MFMailComposeViewController,和

- 将其保存在一个静态变量中,然后,

- 无论何时需要,获取静态MFMailComposeViewController实例并使用它.

并且你几乎肯定必须在每次使用后循环全​​局MFMailComposeViewController.重复使用同一个是可靠的.

有一个全局例程,释放然后重新初始化单例MFMailComposeViewController.在完成邮件编写器之后,每次调用该全局例程.

在任何单身人士中做到这一点.不要忘记你的应用代表当然是一个单身人士,所以在那里做...

@property (nonatomic, strong) MFMailComposeViewController *globalMailComposer;

-(BOOL)application:(UIApplication *)application
   didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
    {
    ........
    // part 3, our own setup
    [self cycleTheGlobalMailComposer];
    // needed due to the worst programming in the history of Apple
    .........
    }
Run Code Online (Sandbox Code Playgroud)

和...

-(void)cycleTheGlobalMailComposer
    {
    // cycling GlobalMailComposer due to idiotic iOS issue
    self.globalMailComposer = nil;
    self.globalMailComposer = [[MFMailComposeViewController alloc] init];
    }
Run Code Online (Sandbox Code Playgroud)

然后使用邮件,像这样......

-(void)helpEmail
    {
    // APP.globalMailComposer IS READY TO USE from app launch.
    // recycle it AFTER OUR USE.

    if ( [MFMailComposeViewController canSendMail] )
        {
        [APP.globalMailComposer setToRecipients:
              [NSArray arrayWithObjects: emailAddressNSString, nil] ];
        [APP.globalMailComposer setSubject:subject];
        [APP.globalMailComposer setMessageBody:msg isHTML:NO];
        APP.globalMailComposer.mailComposeDelegate = self;
        [self presentViewController:APP.globalMailComposer
             animated:YES completion:nil];
        }
    else
        {
        [UIAlertView ok:@"Unable to mail. No email on this device?"];
        [APP cycleTheGlobalMailComposer];
        }
    }

-(void)mailComposeController:(MFMailComposeViewController *)controller
     didFinishWithResult:(MFMailComposeResult)result
     error:(NSError *)error
    {
    [controller dismissViewControllerAnimated:YES completion:^
        { [APP cycleTheGlobalMailComposer]; }
        ];
    }
Run Code Online (Sandbox Code Playgroud)

{nb,修正了下面迈克尔萨拉蒙的拼写错误.}

为方便起见,在前缀文件中有以下宏

#define APP ((AppDelegate *)[[UIApplication sharedApplication] delegate])
Run Code Online (Sandbox Code Playgroud)

这也是一个"小"问题,可能花费你几天:https://stackoverflow.com/a/17120065/294884


仅2016年FTR这里是发送电子邮件IN APP的基本快速代码,

class YourClass:UIViewController, MFMailComposeViewControllerDelegate
 {
    func clickedMetrieArrow()
        {
        print("click arrow!  v1")
        let e = MFMailComposeViewController()
        e.mailComposeDelegate = self
        e.setToRecipients( ["help@smhk.com"] )
        e.setSubject("Blah subject")
        e.setMessageBody("Blah text", isHTML: false)
        presentViewController(e, animated: true, completion: nil)
        }

    func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?)
        {
        dismissViewControllerAnimated(true, completion: nil)
        }
Run Code Online (Sandbox Code Playgroud)

然而!注意!

这些天发送电子邮件"在应用程序中"很糟糕.

简单地切换到电子邮件客户端今天要好得多.

添加到plist ...

<key>LSApplicationQueriesSchemes</key>
 <array>
    <string>instagram</string>
 </array>
Run Code Online (Sandbox Code Playgroud)

然后代码就像

func pointlessMarketingEmailForClient()
    {
    let subject = "Some subject"
    let body = "Plenty of <i>email</i> body."

    let coded = "mailto:blah@blah.com?subject=\(subject)&body=\(body)".stringByAddingPercentEncodingWithAllowedCharacters(.URLQueryAllowedCharacterSet())

    if let emailURL:NSURL = NSURL(string: coded!)
        {
        if UIApplication.sharedApplication().canOpenURL(emailURL)
            {
            UIApplication.sharedApplication().openURL(emailURL)
            }
        else
            {
            print("fail A")
            }
        }
    else
        {
        print("fail B")
        }
    }
Run Code Online (Sandbox Code Playgroud)

这些天,这比尝试从应用程序"内部"发送电子邮件要好得多.

再次记住,iOS模拟器根本没有电子邮件客户端(也不能使用应用程序中的作曲家发送电子邮件).您必须在设备上进行测试.


Rik*_*les 17

它与Swift无关.邮件作曲家的问题似乎永远存在.那个东西非常挑剔,从失败的超时到发送委托消息,即使被取消.

每个人使用的解决方法是创建一个全局邮件编写器(例如在单例中),并在每次需要时重新初始化它.这确保了邮件编写器在操作系统需要时始终处于运行状态,而且当您想要重用它时它也没有任何废话.

因此,创建一个包含邮件编辑器的强大(尽可能全局)变量,并在每次要使用它时重置它.

  • 我有同样的问题 - 只在iOS8上.我的代码是ObjC,所以不应该责怪Swift. (3认同)
  • 嗯,只是在硬件上尝试过,它工作正常.似乎只在iOS8模拟器中出现问题. (2认同)

小智 6

  • XCode 6 Simulator在管理Mailcomposer和其他事情时遇到问题.
  • 尝试使用真实设备测试代码.可能它会起作用.
  • 从actionSheet按钮运行MailComposer时遇到问题,也有真正的测试.IOS 7工作正常,IOS 8中的相同代码不起作用.对我来说,Apple必须对XCode 6进行限制.(使用Objective-C和Swift的太多不同的模拟设备......)