如何从 class 邮件中关闭 MFMailComposeViewController?

How to dismiss MFMailComposeViewController from class mail?

我已将邮件功能从我的 UIviewController 中分离出来,并将它们放入 class“邮件”中。工作正常,但现在我确实无法关闭我的“MFMailComposeViewController”。未调用委托“mailComposeController”,有什么解决办法吗?

import Foundation
import MessageUI


class Mail: UIViewController, MFMailComposeViewControllerDelegate{

    static func createMail2(
        fromViewController:UIViewController,
        recipients  :String,
        messageTitle:String,
        messageText :String,
        attachment  :AnyObject?)
    {

        
        if MFMailComposeViewController.canSendMail() {
            let mail = MFMailComposeViewController()
            //mail.mailComposeDelegate = self //Cannot assign value of type 'Mail.Type' to type 'MFMailComposeViewControllerDelegate?'
            mail.mailComposeDelegate? = fromViewController as! MFMailComposeViewControllerDelegate //added ? (optional)
            

            mail.setToRecipients([recipients])   //(["mail@to.me"])
            mail.setSubject(messageTitle)        //("your subject text")
            mail.setMessageBody(messageText, isHTML: false)
            
            //ggf. Attachment beifügen>>>
            if attachment != nil {
                //attachment vorhanden, also anhängen
                
                let attachName = "\(messageTitle).pdf"
                
                mail.addAttachmentData(
                    attachment as! Data,
                    mimeType: "application/octet-stream", //für binäre Daten, funktioniert immer
                    fileName: attachName)
            }//end if attachment
            //<<<ggf. Attachment beifügen

            
            // Present the view controller modally
            fromViewController.present(mail, animated: true)  //show mail
        } else {
            // show failure alert
            print("Mail services are not available")
            
            let alert = UIAlertController(title: "Mail error", message: "Your device has not been configured to send e-mails", preferredStyle: .alert)
            let okAction = UIAlertAction(title: "OK", style: .default, handler: nil)
            alert.addAction(okAction)
            fromViewController.present(alert,animated: true, completion: nil)
        }//end if else
    }//end func createMail
    
    
    //mail delegate
    func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
        //It’s called when the user dismisses the controller, either by sending the email or canceling the action. Either way, you have to dismiss the controller manually.
        
        //ggf. noch aktionen...
        
        controller.dismiss(animated: true) //remove the mail view
    }//end func mailComposeController
}//end class Mail

您作为 fromViewController 的参数传递的 UIViewController 应该符合 MFMailComposeViewControllerDelegate 协议并且您应该在该控制器的定义中实现 mailComposeController(_: didFinishWith: .

class Mail: UIViewController {

    static func createMail2(
        fromViewController: UIViewController,
        recipients  :String,
        messageTitle:String,
        messageText :String,
        attachment  :AnyObject?) {

        if MFMailComposeViewController.canSendMail() {
            let mail = MFMailComposeViewController()
            if let fromViewController = fromViewController as? MFMailComposeViewControllerDelegate {
                mail.mailComposeDelegate = fromViewController
            } else {
                print("fromViewController needs to conform to MFMailComposeViewControllerDelegate")
            }
            //...
        }
    }
}

您需要创建邮件控制器的静态共享实例并将 if 设置为 mailComposeDelegate。您还应该在邮件控制器中创建一个控制器 属性 以保留对调用邮件编辑器的视图控制器的引用,并将您的 createMail 声明为实例方法(非静态):

import UIKit
import MessageUI

class MailComposer: NSObject, MFMailComposeViewControllerDelegate {
    static let shared = MailComposer()
    private var controller: UIViewController?
    func compose(controller: UIViewController, recipients: String,
                 messageTitle: String, messageText: String, fileURL: URL? = nil) { //, completion: @escaping ((MFMailComposeResult, Error?) -> Void)) {
        self.controller = controller
        if MFMailComposeViewController.canSendMail() {
            let mail = MFMailComposeViewController()
            mail.mailComposeDelegate = MailComposer.shared
            mail.setToRecipients([recipients])
            mail.setSubject(messageTitle)
            mail.setMessageBody(messageText, isHTML: false)
            if let fileURL = fileURL {
                do {
                    try mail.addAttachmentData(Data(contentsOf: fileURL), mimeType: "application/octet-stream", fileName: fileURL.lastPathComponent)
                } catch {
                    print(error)
                }
            }
            controller.present(mail, animated: true)
        } else {
            let alertController = UIAlertController(title: "Mail Compose Error",
                message: "Your device has not been configured to send e-mails",
                preferredStyle: .alert)
            alertController.addAction(.init(title: "OK", style: .default) { _ in
                alertController.dismiss(animated: true)
            })
            controller.present(alertController, animated: true)
        }
    }
    func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
        // You should switch the result only after dismissing the controller
        controller.dismiss(animated: true) {
            let message: String
            switch result {
            case .sent: message = "Message successfully sent!"
            case .saved: message = "Message saved!"
            case .cancelled: message = "Message Canceled!"
            case .failed:  message = "Unknown Error!"
            @unknown default: fatalError()
            }
            let alertController = UIAlertController(title: "Mail Composer",
                message: message,
                preferredStyle: .alert)
            alertController.addAction(.init(title: "OK", style: .default) { _ in
                alertController.dismiss(animated: true)
            })
            self.controller?.present(alertController, animated: true) {
                self.controller = nil
            }
            
        }
    }
}

用法:

class ViewController: UIViewController {
    override func viewDidLoad() {
           super.viewDidLoad()
    }
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        let recipients = "user@email.com"
        let messageTitle = "New Message"
        let messageText = "Mail Test"
        MailComposer.shared.compose(controller: self, recipients: recipients, messageTitle: messageTitle, messageText: messageText)
    }
}