我有模拟器中的Swift(iOS8)MFMailComposeViewController真正的误解

我创build一个CSV文件,并尝试通过电子邮件发送。 显示发送邮件的窗口,但没有填充电子邮件的正文,也没有附加文件。 应用程序挂起这个屏幕:

prntscr.com/4ikwwm

button“取消”不起作用。 在控制台出现几秒钟后:

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 

有我的代码:

 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!") } } } 

试着改用UIActivityViewController发送邮件:

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

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

 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 

有关于PlugInKit东西。

尝试使用UIDocumentInteractionController而不是UIActivityViewController

 let docController = UIDocumentInteractionController(URL: fileURL) docController.delegate = self docController.presentPreviewAnimated(true) ... func documentInteractionControllerViewControllerForPreview(controller: UIDocumentInteractionController!) -> UIViewController! { return self } 

我看到这个屏幕的内容CSV文件: http : //prntscr.com/4ilgax我按下右上angular的button导出,看到这个屏幕http://prntscr.com/4ilguk我在哪里select邮件和几秒钟我看到http://prntscr.com/4ilh2h然后返回到显示文件的内容! 在控制台中使用与使用UIActivityViewController时相同的消息。

* *重要 – 请勿使用此模拟器。 * *

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

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

但! 看到底部的消息!


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

在早期阶段分配并启动MFMailComposeViewController

把它放在一个静态variables中 ,然后,

– 只要需要,获取静态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 ......... } 

和…

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

然后使用邮件,这样的事情…

 -(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]; } ]; } 

{nb,每个迈克尔Salamone固定错字下面}

在前缀文件中有以下macros为了方便

 #define APP ((AppDelegate *)[[UIApplication sharedApplication] delegate]) 

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


只是2016年FTR这里是基本的SWIFT代码发送电子邮件在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) } 

然而! 注意!

这些天来发送电子邮件“在应用程序”是蹩脚的。

简单地切入电子邮件客户端,今天好多了。

添加到plist …

 <key>LSApplicationQueriesSchemes</key> <array> <string>instagram</string> </array> 

然后代码就像

 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") } } 

现在,这比尝试从应用内部发送电子邮件好得多。

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

它与Swift无关。 邮件composer php的问题似乎永远存在。 这件事是非常挑剔的,从超时失败到发送委托消息,即使取消。

每个人使用的解决方法是创build一个全球邮件编辑器(例如在一个单身人士),每当需要它时,重新初始化它。 这可以确保邮件编辑器始终在操作系统需要的时候,而且当你想要重用邮件时,它也没有任何垃圾。

因此,创build一个强大的(尽可能全局的)variables来保存邮件编辑器,并在每次使用时重置它。

  • XCode 6模拟器在pipe理Mailcomposer和其他东西方面有问题。
  • 尝试使用真实设备testing代码。 可能会起作用。
  • 从actionSheetbutton运行MailComposer时,我也遇到了问题,也是真正的考验。 与IOS 7工作正常,在IOS 8相同的代码不起作用。 对我来说,苹果公司必须对Xcode 6进行净化。(Objective-C和Swift一起使用的模拟器件太多了…)

不确定上述解决scheme中提出的回收是否有必要。 但是你确实需要使用适当的参数。

委托收到一个MFMailComposeViewController* parameter 。 当解散控制器时,你需要使用它而不是self 。 即

代表收到(MFMailComposeViewController *) controller 。 而当你closuresMFMailComposeViewController controller时,你需要使用它来代替self 。 毕竟这是你想要解雇的。

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

为邮件编辑器创build一个属性并在视图中实例化它,而不是在需要邮件编辑器时调用它。

 @property (strong, nonatomic) MFMailComposeViewController *mailController; self.mailController = [[MFMailComposeViewController alloc] init]; [self presentViewController:self.mailController animated:YES completion:^{}]; 

嘿,这是在2天前发布的iOS 8.3解决。

Swift中处理邮件的简单帮助类。 基于乔·布洛的回答。

 import UIKit import MessageUI public class EmailManager : NSObject, MFMailComposeViewControllerDelegate { var mailComposeViewController: MFMailComposeViewController? public override init() { mailComposeViewController = MFMailComposeViewController() } private func cycleMailComposer() { mailComposeViewController = nil mailComposeViewController = MFMailComposeViewController() } public func sendMailTo(emailList:[String], subject:String, body:String, fromViewController:UIViewController) { if MFMailComposeViewController.canSendMail() { mailComposeViewController!.setSubject(subject) mailComposeViewController!.setMessageBody(body, isHTML: false) mailComposeViewController!.setToRecipients(emailList) mailComposeViewController?.mailComposeDelegate = self fromViewController.presentViewController(mailComposeViewController!, animated: true, completion: nil) } else { print("Could not open email app") } } public func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) { controller.dismissViewControllerAnimated(true) { () -> Void in self.cycleMailComposer() } } } 

作为实例variables放在AppDelegate类中,并在需要时调用。