How can I prevent navigationController from falling back to root when disabling MFMailComposeViewController

When I fire an instance of MFMailComposeViewController or MFMessageComposeViewController that is presented modally from the third viewController in the navigation stack, the navigation stack is reset and the root VC is reloaded. How can I prevent this behavior and stay on the original viewController (third VC on the stack)? I get the same behavior if I call fired from a submitted VC, a submitted VC, or a navigation controller.

This has been asked before, but I haven't seen a solution.

The application structure looks like this:

TabBarController
Tab 1 - TripsNavController
    -> Trips IntroductionVC (root VC) segue to:
    -> TripsTableViewController segue to:
    -> TripEditorContainerVC
         - TripEditorVC (child of ContainerVC)
         - HelpVC (child of ContainerVC)
Tab 2...
Tab 3...
Tab 4...

      

In TripEditorVC, I represent MFMailComposeViewController. The functions below are declared in a UIViewController extension that accepts the MFMailComposeViewControllerDelegate protocol

func shareWithEmail(message: NSAttributedString) {

    guard MFMailComposeViewController.canSendMail() else {
        showServiceError(message: "Email Services are not available")
        return
    }

    let composeVC = MFMailComposeViewController()
    composeVC.setSubject("My Trip Plan")
    composeVC.setMessageBody(getHTMLforAttributedString(attrStr: message), isHTML: true)
    composeVC.mailComposeDelegate = self

    present(composeVC, animated: true, completion: nil)

}

      

Then, in the delegate method, I dismiss the MFMailComposeVC:

public func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {

    switch result {
    case .sent:
        print("Mail sent")
    case .saved:
        print("Mail saved")
    case .cancelled:
        print("Mail cancelled")
    case .failed:
        print("Send mail failed")
    }

    if error != nil {

       showServiceError(message: "Error: \(error!.localizedDescription)")
    }

    dismiss(animated: true, completion: nil)
}

      

I tried submitting and dismissing and getting the same behavior, i.e .: TripsNavController clears the navigation stack and reloads TripsIntroductionVC as its root VC:

self.present(composeVC, animated: true, completion: nil)
self.parent?.present(composeVC, animated: true, completion: nil)
self.parent?.navigationController?.present(composeVC, animated: true, completion: nil)
self.navigationController?.present(composeVC, animated: true, completion: nil)

      

+3


source to share


4 answers


I found a problem with my navigation stack today. I built a simple project that duplicated the tabBarController / NavigationControler architecture of my problematic project, component by component, until the rejection of the MFMailComposeViewController caused my navigation stack to reset, as described in my original post.

This immediately indicates the source of the error. In my UINavigationCotroller subclass, I created the root viewController in code so that I can skip the intro view if the user has set the radio button in the app preferences. To get changes to this switch setup, I called my instance code in viewDidAppear from navigationController. This worked great except when you reject mailComposeVC. The fix was to add a guard statement to the viewDidAppear to return if the viewController's navControllers collection was not empty, and to send and respond to an NSNotification when the toggle was changed.



TopNavigationController class: UINavigationController {

var sectionType: SectionType?
var defaults = UserDefaults.standard
var showIntroFlag: Bool = true

override func viewDidLoad() {
    super.viewDidLoad()

    // Handle initial load of the tab bar controller where we are not sent a sectionType
    if sectionType == nil {
        sectionType = .groups
    }

    setShowIntroFlag()

    NotificationCenter.default.addObserver(self, selector: #selector(resetControllers), name: NSNotification.Name(rawValue: "kUserDidChangeShowIntros"), object: nil)
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(true)

    guard self.viewControllers.isEmpty else {
        return
    }

    loadControllers()
}

func setShowIntroFlag() {
    showIntroFlag = true

    // Check NSUserDefaults to see if we should hide the Intro Views for all sections
    if defaults.bool(forKey: "SHOW_SECTION_INTROS") == false {
        showIntroFlag = false
    }
}

func loadControllers() {
    if showIntroFlag == true {
        showIntro()
    } else {
        skipIntro()
    }
}

func resetControllers() {
    setShowIntroFlag()
    loadControllers()
}

      

0


source


You can also check with the method presentingViewController?.dismiss

to get a solution.

I tried using the following navigation stack.

Navigation stack



I can successfully send email using the Send Email button using just your code.

Can you inspect and test the navigation flow?

Please let me know if you still face any problem.

+1


source


dismissal (animated: true, completion: zero)

to

self.dismiss (animated: true, completion: zero)

try it

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let secondViewController =     storyboard.instantiateViewControllerWithIdentifier("secondViewControllerId") as! SecondViewController
self.presentViewController(secondViewController, animated: true, completion: nil)

      

or

fooobar.com/questions/72546 / ...

0


source


Just use Unwind Segue its Pretty simple and perfect in your case

I have used it many times.


just look at this example unwind segue.If you still can't find the answer or can't figure out Unwind segue then just answer me.

Hope this solves your problem.

0


source







All Articles