1

I have created a utility class for sending mail and sms. This is the complete code.

class Utility: NSObject, MFMailComposeViewControllerDelegate, MFMessageComposeViewControllerDelegate
{
    var subject: String!
    var body: String!
    var to: [String]!
    var cc: [String]!
    var viewController: UIViewController!

    // MARK: Email utility

    /// sendEmail : Sends email
    ///
    /// - Parameters:
    ///   - vc: UIViewController from which mail is to be sent
    ///   - subj: Email subject
    ///   - emailBody: Email body
    ///   - toRecipients: To recipients
    ///   - ccRecipients: CC recipients
    func sendEmail(vc: UIViewController, subj: String, emailBody: String, toRecipients: [String], ccRecipients: [String])
    {
        self.subject = subj
        self.body = emailBody
        self.to = toRecipients
        self.cc = ccRecipients
        self.viewController = vc
        let mailComposeViewController = configuredMailComposeViewController()
        if MFMailComposeViewController.canSendMail() {
            self.viewController.present(mailComposeViewController, animated: true, completion: nil)
        } else {
            self.showSendMailErrorAlert()
        }
    }


    /// Show error alert when email could not be sent
    func showSendMailErrorAlert() {
        let alert = UIAlertController(title: "Could Not Send Email", message: "Your device could not send e-mail.  Please check e-mail configuration and try again.", preferredStyle: UIAlertControllerStyle.alert)
        alert.addAction(UIAlertAction(title: "Ok", style: UIAlertActionStyle.default, handler: nil))
        self.viewController.present(alert, animated: true, completion: nil)
    }


    /// configuredMailComposeViewController : Set up mail compose view controller
    ///
    /// - Returns: <#return value description#>
    func configuredMailComposeViewController() -> MFMailComposeViewController {
        let mailComposerVC = MFMailComposeViewController()
        mailComposerVC.mailComposeDelegate = self
        mailComposerVC.setToRecipients(self.to)
        mailComposerVC.setCcRecipients(self.cc)
        mailComposerVC.setSubject(self.subject)
        mailComposerVC.setMessageBody(self.body, isHTML: false)

        return mailComposerVC
    }

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

    // MARK: END

    // MARK: SMS utility

    func sendSMS(vc: UIViewController, content: String, phoneNumber: String)
    {
        self.viewController = vc
        if (MFMessageComposeViewController.canSendText()) {
            let messageController = MFMessageComposeViewController()
            messageController.body = content
            messageController.recipients = [phoneNumber]
            messageController.messageComposeDelegate = self
            self.viewController.present(messageController, animated: true, completion: nil)
        }
    }

    func messageComposeViewController(_ controller: MFMessageComposeViewController, didFinishWith result: MessageComposeResult) {
        //... handle sms screen actions
        controller.dismiss(animated: true, completion: nil)
    }

    // MARK: END  

Cancel button on both features is giving crash. As a matter of fact, if I put breakpoint on didFinishWith for both features, the function is not called and crash appears before that.
Strange thing is, if I write this code in UIViewController class, it works fine.

Nitish
  • 13,845
  • 28
  • 135
  • 263
  • Please add the crash log – Subramanian P Jul 03 '17 at 06:27
  • 1
    That's because this is a protocol method. The system calls this method, when you click the cancel button. I think it's a fatal error. Because your method is not adopted by `UIViewController` subclass – Mannopson Jul 03 '17 at 07:59
  • @Mannopson Is there any way I can create a separate utility class for this ? Or should I set the protocols in UIViewController ? – Nitish Jul 03 '17 at 09:35
  • Simply create an extension to your `UIViewController` subclass and you'll be Ok! – Mannopson Jul 03 '17 at 10:15
  • @Nitish I think but I am not 100% sure, but attaching the ` MFMailComposeViewControllerDelegate, MFMessageComposeViewControllerDelegate` delegates directly to your object actually invoke them directly... as such they should only be once you enter your mail or SMS state, if that makes sense. I had this issue with a UIViewController that I was using to call a mail controller and had it attached at the top of the UIViewController and then in the mail controller ofc it would fail when it got to the UIViewController if the user didn't have mail capability to begin with. – petrosmm Jan 19 '19 at 18:41

0 Answers0