Search code examples
iosswiftviewcontrollermfmailcomposeviewcontrollerskscene

Cannot dismiss MFMailComposeViewController that I called from SKScene


I am trying to send an email from within my game app. In one of my SKScenes I have a sprite when you press it, it calls FeedbackVC().sendEmail(). This opens up the email viewController, but it does not dismiss properly. Here is my entire FeedbackVC class. I used the function getTopMostViewController because without it I was getting the error "Warning: Attempt to present on whose view is not in the window hierarchy!". My code will successfully open the MFMailComposeViewController with the prefilled fields and if I press the send button it actually will send to the email to my email, but it won't close and if I try to cancel the email it won't close either. Why won't my viewController close so it will continue back to my game after the email is sent or canceled?

import Foundation
import MessageUI

class FeedbackVC: UINavigationController, MFMailComposeViewControllerDelegate {

    func getTopMostViewController() -> UIViewController? {
        var topMostViewController = UIApplication.shared.keyWindow?.rootViewController
        while let presentedViewController = topMostViewController?.presentedViewController {
            topMostViewController = presentedViewController
        }
        return topMostViewController
    }

    func sendEmail() {
        if MFMailComposeViewController.canSendMail() {
            let mail = MFMailComposeViewController()
            mail.mailComposeDelegate = self

            mail.setToRecipients(["[email protected]"])
            mail.setSubject("In-App Feedback")
            mail.setMessageBody("", isHTML: false)
            self.getTopMostViewController()!.present(mail, animated: true, completion: nil)
        } else {
            print("Failed To Send Email!")
        }
    }

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

I have also tried setting the UINavigationControllerDelegate in the sendEmail() function.

mail.delegate = self as? UINavigationControllerDelegate

I have also tried things like popping the view controller and going back to the top most view controller in the mailComposeController.

popToRootViewContoller(animated: true)

getTopMostViewController()?.dismiss(animated: true, completion: nil)

I've tried following the guide on, https://developer.apple.com/documentation/messageui/mfmailcomposeviewcontroller, but it didn't work as I think my scenario is different since I am going from a SKScene to the MFMailCompose ViewController then back to a SKScene.


Solution

  • I'm one of the other developers working on this project. Posting in case someone has similar problems.

    We were attempting to call our FeedbackVC in a way that looked like this:

    if nodeTapped.name == "Feedback" {
      let vc = FeedbackVC()
      vc.emailButtonTapped(foo)
    }
    
    

    This would create the FeedbackVC class, call the emailButtonTapped method, and then deallocate the class from memory upon exiting the if statement. This means that clicking cancel or send would attempt to access the deallocated space, causing an EXC_BAD_ACCESS error. I fixed this by declaring vc as a class variable instead of declaring it inside the if statement.