由于层次结构问题,无法显示由 MFMailComposeViewController 创建的页面 - Swift 4
Page created by MFMailComposeViewController could not be shown because of hierarchy - Swift 4
我尝试添加一个功能,即在用户触摸 table 中的一行后会弹出一个邮件页面。也就是说,这意味着用户可以在点击该行时激活 "function"(此处该函数的名称为 "orderOfSendAnEmailToReportTheProblem")。我的所有代码如下所示。 (这种代码已经被Whosebug上的几个genii提出了...)
import Foundation
import UIKit
import MessageUI
class ReportProblem : UIViewController, MFMailComposeViewControllerDelegate {
func orderOfSendAnEmailToReportTheProblem() {
let mailComposeViewController = configureMailController()
if MFMailComposeViewController.canSendMail() {
self.present(mailComposeViewController, animated: true, completion: nil)
} else {
showMailError()
}
}
//Activate the series of the commands of sending the email.
func configureMailController() -> MFMailComposeViewController {
let mailComposeVC = MFMailComposeViewController()
mailComposeVC.mailComposeDelegate = self
mailComposeVC.setToRecipients(["my email"])
mailComposeVC.setSubject("Yo")
return mailComposeVC
}
//Set the recipient and the title of this email automatically.
func showMailError() {
let sendMailErrorAlert = UIAlertController(title: "Could not sned the email.", message: "Oops, something was wrong, please check your internet connection once again.", preferredStyle: .alert)
let dismiss = UIAlertAction(title: "Ok", style: .default, handler: nil)
sendMailErrorAlert.addAction(dismiss)
self.present(sendMailErrorAlert, animated: true, completion: nil) //If you conform the protocol of NSObject instead of UIViewController, you could not finish this line successfully.
}
//Set a alert window so that it would remind the user when the device could not send the email successfully.
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
//Set this final step so that the device would go to the previous window when you finish sending the email.
}
但是,出现了问题。当我在我的真实设备上测试它时,在我点击那个特定的行之后,没有任何反应,没有弹出任何新页面...... Xcode 只显示 "Warning: Attempt to present on whose view is not in the window hierarchy!" 我已经尝试了几种方法,例如作为 "view.bringSubview(toFront: mailComposeVC)" 或在我的代码末尾添加下面显示的代码,但没有任何效果。
func topMostController() -> UIViewController {
var topController: UIViewController = UIApplication.shared.keyWindow!.rootViewController!
while (topController.presentedViewController != nil) {
topController = topController.presentedViewController!
}
return topController
}
我注意到有些人在创建alert时也会遇到类似的问题window,解决方法是创建一个独立的UIWindow,但我想用mailComposeController来呈现电子邮件页面。其他一些人也面临一些关于 MFMailComposeViewController 的问题,但他们的问题与层次结构无关。我是swift的新手,被这个问题困扰了一整天。。。我用swift4开发了我的App,有大神知道怎么解决这个问题么。。。 .
所以现在我正在编写另一种方式来呈现我用于通用视图的方式。
在另一个 class 中有一些代码用于呈现视图,以便您可以使用这两种方法在整个应用程序中重复使用它们。
func slideInFromRight(parentView:UIView,childView:UIView) {
childView.transform = CGAffineTransform(translationX: parentView.frame.maxX, y: 0)
parentView.addSubview(childView)
UIView.animate(withDuration: 0.25, animations: {
childView.transform = CGAffineTransform(translationX: 0, y: 0)
})
}
func slideOutToRight(view:UIView) {
UIView.animate(withDuration: 0.25, animations: {
view.transform = CGAffineTransform(translationX: view.frame.maxX, y: 0)
},completion:{(completed:Bool) in
view.removeFromSuperview()
})
}
现在使用这些方法来呈现和移除自定义视图控制器,如下所示
let window = UIApplication.shared.keyWindow
let vc = YourViewController().instantiate()
self.addChildViewController(vc)
let view = vc.view
view.frame = CGRect(x: 0, y: 20, width: window!.frame.width, height: window!.frame.height-20)
//Here Animation is my custom presenter class and shared is it's shared instance.
Animation.shared.slideInFromRight(parentView: window!, childView: view)
//Or you can use current View controller's view
Animation.shared.slideInFromRight(parentView: self.view!, childView: view)
天才 Vivek Singh,你的方法看起来不错,但有点乏味。而且,它在我的项目中仍然没有工作......(似乎你使用了一些关于UIView的代码,例如parentView
,childView
和view
。但是,我使用了MFMailComposeViewController
好像和原来的看法有点不一样...不知道这个理论对不对...)
不过,我找到了解决办法。我推测问题是当用户点击另一个tableViewController中的行后(这里是SettingTVController
),它会激活"another " [=27=中的函数“orderOfSendAnEmailToReportTheProblem( )
” ](这里是ReportProblem
)。因为有两个不同的viewController,所以发生了某种冲突。
因此,我将我在上述问题中发布的所有代码移动到我原来的tableViewController,这样用户在激活功能时就不会进入另一个viewController,并且不再存在层次结构问题。
import UIKit
import StoreKit
import MessageUI
class SettingTVController: UITableViewController, MFMailComposeViewControllerDelegate {
var settingTitleConnection = showData()
override func viewDidLoad() {
//skip
}
override func didReceiveMemoryWarning() {
//skip
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//skip
}
override func numberOfSections(in tableView: UITableView) -> Int {
//skip
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//skip
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView.indexPathForSelectedRow?.row == 2 && tableView.indexPathForSelectedRow?.section == 1 {
orderOfSendAnEmailToReportTheProblem()
} else {
//skip
}
tableView.deselectRow(at: indexPath, animated: true)
}
//-----<The codes below is used to construct the function of reporting problem with email>-----
func orderOfSendAnEmailToReportTheProblem() {
let mailComposeViewController = configureMailController()
self.present(mailComposeViewController, animated: true, completion: nil)
if MFMailComposeViewController.canSendMail() {
self.present(mailComposeViewController, animated: false, completion: nil)
} else {
showMailError()
}
}
//Activate the series of the commands of sending the email.
func configureMailController() -> MFMailComposeViewController {
let mailComposeVC = MFMailComposeViewController()
mailComposeVC.mailComposeDelegate = self
mailComposeVC.setToRecipients(["datototest@icloud.com"])
mailComposeVC.setSubject("Reporting of Problems of Rolling")
return mailComposeVC
}
//Set the recipient and the title of this email automatically.
func showMailError() {
let sendMailErrorAlert = UIAlertController(title: "Could not send the email.", message: "Oops, something was wrong, please check your internet connection once again.", preferredStyle: .alert)
let dismiss = UIAlertAction(title: "Ok", style: .default, handler: nil)
sendMailErrorAlert.addAction(dismiss)
self.present(sendMailErrorAlert, animated: true, completion: nil) //If you conform the protocol of NSObject instead of UIViewController, you could not finish this line successfully.
}
//Set a alert window so that it would remind the user when the device could not send the email successfully.
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true, completion: nil)
//UIApplication.shared.keyWindow?.rootViewController?.dismiss(animated: true, completion: nil)
}
//Set this final step so that the device would go to the previous window when you finish sending the email.
//-----<The codes above is used to construct the function of reporting problem with email>-----
}
我把我的代码贴在上面,希望有一天能帮助其他遇到类似问题的人。再次感谢您的帮助!!
我不知道您为什么会遇到视图层次结构问题。但我能够在 swift 4 中实现邮件共享选项。我遵循完全相同的步骤。
检查是否可以发送邮件:
MFMailComposeViewController.canSendMail()
配置邮件正文:
private func configureMailController() -> MFMailComposeViewController {
let mailComposeViewController = MFMailComposeViewController()
mailComposeViewController.mailComposeDelegate = self
mailComposeViewController.setMessageBody("MESSAGE BODY", isHTML: true)
return mailComposeViewController
}
当前邮件VC:
present(mailComposeViewController, animated: true)
确认可选协议并明确取消视图:
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true)
}
我尝试添加一个功能,即在用户触摸 table 中的一行后会弹出一个邮件页面。也就是说,这意味着用户可以在点击该行时激活 "function"(此处该函数的名称为 "orderOfSendAnEmailToReportTheProblem")。我的所有代码如下所示。 (这种代码已经被Whosebug上的几个genii提出了...)
import Foundation
import UIKit
import MessageUI
class ReportProblem : UIViewController, MFMailComposeViewControllerDelegate {
func orderOfSendAnEmailToReportTheProblem() {
let mailComposeViewController = configureMailController()
if MFMailComposeViewController.canSendMail() {
self.present(mailComposeViewController, animated: true, completion: nil)
} else {
showMailError()
}
}
//Activate the series of the commands of sending the email.
func configureMailController() -> MFMailComposeViewController {
let mailComposeVC = MFMailComposeViewController()
mailComposeVC.mailComposeDelegate = self
mailComposeVC.setToRecipients(["my email"])
mailComposeVC.setSubject("Yo")
return mailComposeVC
}
//Set the recipient and the title of this email automatically.
func showMailError() {
let sendMailErrorAlert = UIAlertController(title: "Could not sned the email.", message: "Oops, something was wrong, please check your internet connection once again.", preferredStyle: .alert)
let dismiss = UIAlertAction(title: "Ok", style: .default, handler: nil)
sendMailErrorAlert.addAction(dismiss)
self.present(sendMailErrorAlert, animated: true, completion: nil) //If you conform the protocol of NSObject instead of UIViewController, you could not finish this line successfully.
}
//Set a alert window so that it would remind the user when the device could not send the email successfully.
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true, completion: nil)
}
//Set this final step so that the device would go to the previous window when you finish sending the email.
}
但是,出现了问题。当我在我的真实设备上测试它时,在我点击那个特定的行之后,没有任何反应,没有弹出任何新页面...... Xcode 只显示 "Warning: Attempt to present on whose view is not in the window hierarchy!" 我已经尝试了几种方法,例如作为 "view.bringSubview(toFront: mailComposeVC)" 或在我的代码末尾添加下面显示的代码,但没有任何效果。
func topMostController() -> UIViewController {
var topController: UIViewController = UIApplication.shared.keyWindow!.rootViewController!
while (topController.presentedViewController != nil) {
topController = topController.presentedViewController!
}
return topController
}
我注意到有些人在创建alert时也会遇到类似的问题window,解决方法是创建一个独立的UIWindow,但我想用mailComposeController来呈现电子邮件页面。其他一些人也面临一些关于 MFMailComposeViewController 的问题,但他们的问题与层次结构无关。我是swift的新手,被这个问题困扰了一整天。。。我用swift4开发了我的App,有大神知道怎么解决这个问题么。。。 .
所以现在我正在编写另一种方式来呈现我用于通用视图的方式。 在另一个 class 中有一些代码用于呈现视图,以便您可以使用这两种方法在整个应用程序中重复使用它们。
func slideInFromRight(parentView:UIView,childView:UIView) {
childView.transform = CGAffineTransform(translationX: parentView.frame.maxX, y: 0)
parentView.addSubview(childView)
UIView.animate(withDuration: 0.25, animations: {
childView.transform = CGAffineTransform(translationX: 0, y: 0)
})
}
func slideOutToRight(view:UIView) {
UIView.animate(withDuration: 0.25, animations: {
view.transform = CGAffineTransform(translationX: view.frame.maxX, y: 0)
},completion:{(completed:Bool) in
view.removeFromSuperview()
})
}
现在使用这些方法来呈现和移除自定义视图控制器,如下所示
let window = UIApplication.shared.keyWindow
let vc = YourViewController().instantiate()
self.addChildViewController(vc)
let view = vc.view
view.frame = CGRect(x: 0, y: 20, width: window!.frame.width, height: window!.frame.height-20)
//Here Animation is my custom presenter class and shared is it's shared instance.
Animation.shared.slideInFromRight(parentView: window!, childView: view)
//Or you can use current View controller's view
Animation.shared.slideInFromRight(parentView: self.view!, childView: view)
天才 Vivek Singh,你的方法看起来不错,但有点乏味。而且,它在我的项目中仍然没有工作......(似乎你使用了一些关于UIView的代码,例如parentView
,childView
和view
。但是,我使用了MFMailComposeViewController
好像和原来的看法有点不一样...不知道这个理论对不对...)
不过,我找到了解决办法。我推测问题是当用户点击另一个tableViewController中的行后(这里是SettingTVController
),它会激活"another " [=27=中的函数“orderOfSendAnEmailToReportTheProblem( )
” ](这里是ReportProblem
)。因为有两个不同的viewController,所以发生了某种冲突。
因此,我将我在上述问题中发布的所有代码移动到我原来的tableViewController,这样用户在激活功能时就不会进入另一个viewController,并且不再存在层次结构问题。
import UIKit
import StoreKit
import MessageUI
class SettingTVController: UITableViewController, MFMailComposeViewControllerDelegate {
var settingTitleConnection = showData()
override func viewDidLoad() {
//skip
}
override func didReceiveMemoryWarning() {
//skip
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
//skip
}
override func numberOfSections(in tableView: UITableView) -> Int {
//skip
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
//skip
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if tableView.indexPathForSelectedRow?.row == 2 && tableView.indexPathForSelectedRow?.section == 1 {
orderOfSendAnEmailToReportTheProblem()
} else {
//skip
}
tableView.deselectRow(at: indexPath, animated: true)
}
//-----<The codes below is used to construct the function of reporting problem with email>-----
func orderOfSendAnEmailToReportTheProblem() {
let mailComposeViewController = configureMailController()
self.present(mailComposeViewController, animated: true, completion: nil)
if MFMailComposeViewController.canSendMail() {
self.present(mailComposeViewController, animated: false, completion: nil)
} else {
showMailError()
}
}
//Activate the series of the commands of sending the email.
func configureMailController() -> MFMailComposeViewController {
let mailComposeVC = MFMailComposeViewController()
mailComposeVC.mailComposeDelegate = self
mailComposeVC.setToRecipients(["datototest@icloud.com"])
mailComposeVC.setSubject("Reporting of Problems of Rolling")
return mailComposeVC
}
//Set the recipient and the title of this email automatically.
func showMailError() {
let sendMailErrorAlert = UIAlertController(title: "Could not send the email.", message: "Oops, something was wrong, please check your internet connection once again.", preferredStyle: .alert)
let dismiss = UIAlertAction(title: "Ok", style: .default, handler: nil)
sendMailErrorAlert.addAction(dismiss)
self.present(sendMailErrorAlert, animated: true, completion: nil) //If you conform the protocol of NSObject instead of UIViewController, you could not finish this line successfully.
}
//Set a alert window so that it would remind the user when the device could not send the email successfully.
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true, completion: nil)
//UIApplication.shared.keyWindow?.rootViewController?.dismiss(animated: true, completion: nil)
}
//Set this final step so that the device would go to the previous window when you finish sending the email.
//-----<The codes above is used to construct the function of reporting problem with email>-----
}
我把我的代码贴在上面,希望有一天能帮助其他遇到类似问题的人。再次感谢您的帮助!!
我不知道您为什么会遇到视图层次结构问题。但我能够在 swift 4 中实现邮件共享选项。我遵循完全相同的步骤。
检查是否可以发送邮件:
MFMailComposeViewController.canSendMail()
配置邮件正文:
private func configureMailController() -> MFMailComposeViewController { let mailComposeViewController = MFMailComposeViewController() mailComposeViewController.mailComposeDelegate = self mailComposeViewController.setMessageBody("MESSAGE BODY", isHTML: true) return mailComposeViewController
}
当前邮件VC:
present(mailComposeViewController, animated: true)
确认可选协议并明确取消视图:
func mailComposeController(_ controller: MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) { controller.dismiss(animated: true)
}