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 = ["[email protected]"]
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: "[email protected]")
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?
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: "[email protected]")
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: "[email protected]")
self.mailSender.presentOverViewController(viewController: self)
}
}