在解除MFMailComposeViewController时,如何防止navigationController返回到root

时间:2017-06-16 19:21:00

标签: ios swift3

当我解除从导航堆栈中的第三个viewController以模态方式呈现的MFMailComposeViewController或MFMessageComposeViewController的实例时,将重置导航堆栈,并重新加载根VC。如何防止此行为并保留在原始呈现的viewController(堆栈中的第三个VC)?无论我是从演示VC,演示的VC还是navigationController调用dismiss,我都会得到相同的行为。

以前曾经问过,但我没有看到解决方案。

App Structure看起来像这样:

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...

在TripEditorVC中,我展示了MFMailComposeViewController。下面的函数在UIViewController的扩展中声明,它采用MFMailComposeViewControllerDelegate协议

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)

}

然后在委托方法中我解雇了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)
}

我尝试过以下方法来呈现和解散并获得相同的行为,即:TripsNavController清除导航堆栈并重新加载TripsIntroductionVC作为其根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)

4 个答案:

答案 0 :(得分:1)

您还可以使用presentingViewController?.dismiss方法进行检查以获得解决方案。

我尝试过以下导航堆栈。

Navigation Stack

我可以使用您的代码从Container VC的“发送电子邮件”按钮成功发送电子邮件。

请检查并验证导航流程吗?

如果您仍然遇到任何问题,请告诉我。

答案 1 :(得分:0)

解雇(动画:真实,完成:无)

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

试试这个

spring.cloud.stream.bindings.toGreeting.contentType=avro/bytes

https://stackoverflow.com/a/37740006/8196100

答案 2 :(得分:0)

Just Unwind Segue在您的案例中非常简单和完美

我已多次使用..

看看这个Unwind segue's example 。如果您仍然无法找到答案或无法理解Unwind segue,那么请回复我。

希望这能解决您的问题。

答案 3 :(得分:0)

我今天发现了导航堆栈的问题。我建了一个简单的 项目复制我的问题项目的tabBarController / NavigationControler架构,逐个组件,直到解雇MFMailComposeViewController导致我的导航堆栈重置,如我原来的帖子所述。

这立即指出了bug的来源。在我的子类UINavigationCotroller中,我在代码中实例化了根viewController,这样如果用户在应用程序设置中设置了一个开关,我就可以跳过介绍性视图。为了获取该开关设置中的更改,我在navigationController的viewDidAppear中调用了我的实例化代码。在解雇mailComposeVC时,除了解决方案外,它工作正常。修复是在viewDidAppear中添加一个guard语句,如果navControllers viewController集合不为空则返回,并在交换机发生更改时发送并响应NSNotification。

class TopNavigationController: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()
}