0

I am doing a screen that allows users to send mail. I wrote some code for it and it works fine:

import UIKit
import MessageUI

class ViewController: UIViewController, MFMailComposeViewControllerDelegate {

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        let mailComposer = MFMailComposeViewController()
        mailComposer.mailComposeDelegate = self
        let recipients = ["fresher40@gmail.com"]
        mailComposer.setToRecipients(recipients)
        mailComposer.setSubject("Title")
        mailComposer.setMessageBody("Hello", isHTML: false)
        if MFMailComposeViewController.canSendMail() {
            self.present(mailComposer, animated: true, completion: nil)
        }
    }

    func mailComposeController(
        _ controller: MFMailComposeViewController,
        didFinishWith result: MFMailComposeResult,
        error: Error?
        ) {
        controller.dismiss(animated: true, completion: nil)
    }
}

Then I tried to move the functional of mail sending in another class named "MailSender". So it looks like:

import UIKit
import MessageUI

class MailSender: NSObject, MFMailComposeViewControllerDelegate {

    private var mailComposer = MFMailComposeViewController()

    init(email: String) {
        super.init()
        mailComposer.mailComposeDelegate = self
        let recipients = [email]
        mailComposer.setToRecipients(recipients)
        mailComposer.setSubject("Title")
        mailComposer.setMessageBody("Hello", isHTML: false)
    }

    func presentOverViewController(viewController: UIViewController) {
        if MFMailComposeViewController.canSendMail() {
            viewController.present(mailComposer, animated: true, completion: nil)
        }
    }

    func mailComposeController(
        _ controller: MFMailComposeViewController,
        didFinishWith result: MFMailComposeResult,
        error: Error?
        ) {
        controller.dismiss(animated: true, completion: nil)
    }
}

My view controller looks this way:

import UIKit
import MessageUI

class ViewController: UIViewController {

    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        let mailSender = MailSender(email: "someEmail@gmail.com")
        mailSender.presentOverViewController(viewController: self)
    }
}

In this case the screen opens sending mail view, but after cancel tap button the application crashes. What am I doing wrong?

Sergey Polozov
  • 225
  • 1
  • 11
  • 1
    Update your question with details of the crash. Include the complete error message and point out the exact line of code causing the crash. – rmaddy Jun 15 '18 at 23:44

1 Answers1

1

The problem is probably that mailSender is a local that vanished before it has time to do anything:

class ViewController: UIViewController {
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        let mailSender = MailSender(email: "someEmail@gmail.com")
        mailSender.presentOverViewController(viewController: self)
    }
}

Thus you end up with the delegate pointing at a nonexistent object — a simple recipe for a crash when the user cancels and the mail compose view controller tries to talk to that delegate. I would suggest making it an instance property:

class ViewController: UIViewController {
    var mailSender : MailSender!
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        self.mailSender = MailSender(email: "someEmail@gmail.com") 
        self.mailSender.presentOverViewController(viewController: self)
    }
}
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • There are other things about your new architecture that look rather risky to me, but at least this should take care of the crash. – matt Jun 16 '18 at 00:03
  • What else? Here I have past not actual code, just for example. Or you are talking exactly about the class MailSender ? – Sergey Polozov Jun 16 '18 at 00:05
  • I mean things like: should it be a class? Should it persist and reuse the MFMailComposeViewController? I think it should behave much more like your original code did. – matt Jun 16 '18 at 00:32