bevbomb
bevbomb

Reputation: 709

MFMailComposeViewControllerDelegate not working Swift 3

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 = ["[email protected]"]
    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)
}

Upvotes: 6

Views: 4875

Answers (5)

Vlad
Vlad

Reputation: 221

Adding

#import <MessageUI/MessageUI.h> 

to the AppName-Bridging-Header.h did the job !

Upvotes: 1

mkz
mkz

Reputation: 2302

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(["[email protected]"])
    mailComposeViewController.setSubject("subject")
    mailComposeViewController.setMessageBody("test body", isHTML: false)
    return mailComposeViewController
}()

Solution:

func createMailComposeViewController() -> MFMailComposeViewController {
    let mailComposeViewController = MFMailComposeViewController()
    mailComposeViewController.mailComposeDelegate = self
    mailComposeViewController.setToRecipients(["[email protected]"])
    mailComposeViewController.setSubject("subject")
    mailComposeViewController.setMessageBody("test body", isHTML: false)
    return mailComposeViewController
}

Upvotes: 3

Klajd Deda
Klajd Deda

Reputation: 375

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.

Upvotes: 1

videolist
videolist

Reputation: 217

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)

Upvotes: 7

Deyton
Deyton

Reputation: 2368

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

Upvotes: 3

Related Questions