I converted my app to swift 3.0 and have a problem with MailComposeController. When I call function:
`func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?){
controller.dismiss(animated: true, completion: nil)
}`
first of all I have an error with info:
what is strange for my, becouse I copy and paste this method from MFMailComposeViewControllerDelegate. When I change Error to NSError it works, but I receive a warning with info, this method needs to be private to avoid this warning.
When I'm in mailComposer and see email and try to tap Cancel this controller doesn't disapear. Any solution how to dismiss this controller?
I had the same problem because I was importing RealmSwift, which has its own Error struct.
Fix it by specifying which Error type you want. In this case, Swift.Error.
Full Code:
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Swift.Error?){
controller.dismiss(animated: true, completion: nil)
}
Related
I'm trying to implement the feature where user can invite friends on App via Messages and Email.
I am using MFMessageComposeViewController for message and MFMailComposeViewController for email.
For messages in delegate method
func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
if result == .sent {
updateAndStoreInvitation(controller.recipients)
}
dismiss(animated: true)
}
we get the recipients and store them to show that this user already invited.
but for email case
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
if result == .sent {
}
dismiss(animated: true)
}
does not provide recipients list.
is there any way to get recipients list in MFMailComposeViewController in delegate method on result == .sent
I have the following code in my app to send an e-Mail:
let ToRecipents = ["recipient here"]
let subject = "subject here"
let MessageBody = "message here"
let mc : MFMailComposeViewController = MFMailComposeViewController()
mc.mailComposeDelegate = self
mc.setToRecipients(ToRecipents)
mc.setSubject(subject)
mc.setMessageBody(MessageBody, isHTML: false)
self.present(mc, animated: true, completion: nil)
}
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
controller.dismiss(animated: true, completion: nil)
}
I can't seem to get MFMailComposeViewController to dismiss, what am I doing wrong??
In a general way when delegate methods are not called:
• Check if the delegate is set. You do it correctly with mc.mailComposeDelegate = self
• Check if the delegate method you set is compliant with the protocol.
• Check if the delegate method is correctly implemented (that's where lies your issue) in that object you passed as delegate. Read the doc, or remove the method declaration and let the compiler/IDE/XCode autocomplete it for you. In Swift between various tutorials they are often issues because Swift 1, Swift 2, Swift 3/4 have renamed the methods and causing issues, tutorial being focused on a Swift version only.
Your method:
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?)
The method from the documentation:
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?)
Since they are not the same, and the iOS SDK should check the if the delegate responds to the correct method, then yours shouldn't be called because it doesn't match.
I have been using the mail composer in a few of my apps for awhile now and as of recent the mailComposeDelegate no longer gets call.I wasn't sure if this was something to do with the new release of Swift. So, I thought I would ask and see if anyone else is having similar issues.I can present the mail composer but it never gets dismissed due to the delegate not working.
Below is an exact copy of the code I have been using:
func launchFeedback() {
guard MFMailComposeViewController.canSendMail() else {
return
}
let emailTitle = "Feedback"
let messageBody = ""
let toRecipents = ["johnappleseed#icloud.com"]
mailComposer.mailComposeDelegate = self
mailComposer.setSubject(emailTitle)
mailComposer.setMessageBody(messageBody, isHTML: false)
mailComposer.setToRecipients(toRecipents)
self.show(mailComposer, sender: self)
}
func mailComposeController(controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
print(error)
controller.dismiss(animated: true, completion: nil)
}
This is clearly an Xcode bug. The only way to get around this (after searching though StackOverflow life for an hour) was this:
#objc(mailComposeController:didFinishWithResult:error:)
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult,error: NSError?) {
controller.dismiss(animated: true)
}
See the #objc macro before the method implementation. Also note that the last parameter has to be NSError type instead of Error as suggested by Apple documentation (and autocompleted by Xcode)
Swift 3 no longer has unnamed first parameters by default (see this proposal), so you'll need to add an underscore to your function:
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
print(error)
controller.dismiss(animated: true, completion: nil)
}
Swift 4, Xcode 9.1.
My issue was that MFMailComposeViewController was working fine but if you click cancel, dismiss, and then trying to open it one more time both cancel and send button will not fire didFinishWith delegate function.
It was happening because I've declared MFMailComposeViewController as lazy variable and solution was to create new instance of MFMailComposeViewController every time you want to open it.
Problem:
lazy var mailComposeViewController: MFMailComposeViewController = {
let mailComposeViewController = MFMailComposeViewController()
mailComposeViewController.mailComposeDelegate = self
mailComposeViewController.setToRecipients(["example#test.test"])
mailComposeViewController.setSubject("subject")
mailComposeViewController.setMessageBody("test body", isHTML: false)
return mailComposeViewController
}()
Solution:
func createMailComposeViewController() -> MFMailComposeViewController {
let mailComposeViewController = MFMailComposeViewController()
mailComposeViewController.mailComposeDelegate = self
mailComposeViewController.setToRecipients(["example#test.test"])
mailComposeViewController.setSubject("subject")
mailComposeViewController.setMessageBody("test body", isHTML: false)
return mailComposeViewController
}
After wasting 2 good hours, i came to the conclusion that as of Xcode 8.3. MFMailComposeViewController does not work on a mixed swift/objc code base. It pops odd compile errors, which first i thought were due to my stupidity, but no.
This is so frustrating apple. Most of us old timers do have tons of code on obj-c, so a pure swift scenario is close to impossible. So as i move classes to swift i have to deal with extra pain as well.
Adding
#import <MessageUI/MessageUI.h>
to the AppName-Bridging-Header.h did the job !
while sending mail, after tapping send or cancel button view controller stays there and app stalls.
//swift 2.2 ; xcode 7.3.1 ;
if( MFMailComposeViewController.canSendMail() ) {
print("Can send email.")
}
var subjectText = "Verification"
var toReceipients = ["notorious.roman#gmail.com"]
// var msgBody = "Verified"
var mc:MFMailComposeViewController = MFMailComposeViewController()
mc.mailComposeDelegate = self
mc.setSubject(subjectText)
mc.setMessageBody("Verified", isHTML: false)
mc.setToRecipients(toReceipients)
self.presentViewController(mc, animated: true, completion: nil)
}
func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
self.dismissViewControllerAnimated(true, completion: nil)
}
Swift 4.0 Update.
Swift 5.0 Update.
Allow me to add something to the discussion...
In Swift 4 and 5 the delegate method slightly changed; As it's posted by you now, won't do any effect and won't get called. It happened to me, drove me crazy!
The Xcode warning suggest three fixes but first two could be misleading. It's just a tiny fix...
Here's the delegate method fixed for Swift 3, 4 and 5:
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
// Dismiss the mail compose view controller.
controller.dismiss(animated: true, completion: nil)
}
Still, Victor's answer should be the correct/accepted one.
Enjoy!
I think #rmaddy answer your question in his comment, nevertheless I going to explain you what's happening. You're trying to dismiss the UIViewController that presents the MFMailComposeViewController not the MFMailComposeViewController.
As Apple specify in his documentation:
The mail compose view controller is not dismissed automatically. When the user taps the buttons to send the email or cancel the interface, the mail compose view controller calls the mailComposeController:didFinishWithResult:error: method of its delegate. Your implementation of that method must dismiss the view controller explicitly.
So you need to set the method in this way:
func mailComposeController(controller: MFMailComposeViewController, didFinishWithResult result: MFMailComposeResult, error: NSError?) {
// Dismiss the mail compose view controller.
controller.dismissViewControllerAnimated(true, completion: nil)
}
I hope this help you.
is had an Switch Statement that controls it for me:
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
switch result.rawValue {
case MFMailComposeResult.cancelled.rawValue :
print("Cancelled")
case MFMailComposeResult.failed.rawValue :
print("Failed")
case MFMailComposeResult.saved.rawValue :
print("Saved")
case MFMailComposeResult.sent.rawValue :
print("Sent")
default: break
}
self.dismiss(animated: true, completion: nil)
}
I'm trying to allow the user to send multiple text messages in succession in a MFMessageComposeViewController, but if I don't dismiss the controller in the didFinishWithResult delegate method, the Cancel button in the top right corner becomes disabled, and the user has no way of getting out of the text message interface.
Is the MFMessageComposeViewController only for sending one-off messages?
func messageComposeViewController(controller: MFMessageComposeViewController!, didFinishWithResult result: MessageComposeResult) {
if result.value == MessageComposeResultCancelled.value {
self.dismissViewControllerAnimated(true, completion: nil)
}
}
Thanks for the help.