[英]Display an alert using storyboard and custom UITabBarController
我正在处理使用 UITabBarController 的问题。 我有一个使用故事板的小项目(XCode 13,IOS 15 作为基本系统)。 我创建了一个 TabBarController,但后来我发现我无法以编程方式有效地管理它。 阅读各种文档后,我发现我可以使用 storyboard 中的两个场景并以编程方式创建标签栏。 所以我在SceneDelegate.swift
中做了这个:
let queryViewControllerTab = storyBoard.instantiateViewController(withIdentifier: "QueryViewController")
let settingsViewControllerTab = storyBoard.instantiateViewController(withIdentifier: "SettingsViewController")
let starredViewControllerTab = storyBoard.instantiateViewController(withIdentifier: "StarredViewController")
starredViewControllerTab.tabBarItem.title = "Starred"
starredViewControllerTab.tabBarItem.image = UIImage(systemName: "star")
// TODO: Discover why first two views keep reading image I setup previously in storyboard
let tabBarController = UITabBarController()
tabBarController.viewControllers = [queryViewControllerTab, settingsViewControllerTab, starredViewControllerTab]
tabBarController.selectedViewController = settingsViewControllerTab
self.window?.rootViewController = tabBarController
self.window?.makeKeyAndVisible()
这完美地工作,我可以很容易地设置一个条件是否userDefaults
没有设置,直接加载设置。
在我的 class SettingsViewController
我想添加一个动作,在按下按钮时,你会收到一个警报:
@IBAction func saveButtonPressed(_ sender: UIButton) {
// keychain.set(tokenInput.text ?? "", forKey: keychainKey)
let alert = UIAlertController(title: "My Alert", message: "This is an alert.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "Default action"),
style: .default, handler: { _ in
NSLog("The \"OK\" alert occured.")
}))
tabBarController.present(alert, animated: true, completion: nil)
}
但这会使应用程序崩溃, unrecognized selector sent to instance 0x7f82f9705c30'
我试图调试问题,我明白我不能以这种方式发出警报,因为视图实际上是 tabBar 而不是我的场景。 但在这里我卡住了。 我试图在StarredViewController
中实现UITabBarControllerDelegate
,但我无法让它工作。
extension StarredViewController: UITabBarControllerDelegate {
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
print("did select tab bar item!")
}
}
我开始认为我使用SceneDelegate
和AppDelegate
的主要设置是错误的。 我发现的大多数以前的教程或线程似乎都无法编译,因为使用了已弃用的版本。
这是一种从任何呈现的视图 Controller 呈现警报的方法。
添加一些扩展:
import UIKit
extension UIViewController {
var customVisibleViewController: UIViewController? {
if let navigationController = self as? UINavigationController {
return navigationController.topViewController?.customVisibleViewController
} else if let tabBarController = self as? UITabBarController {
return tabBarController.selectedViewController?.customVisibleViewController
} else if let presentedViewController = presentedViewController {
return presentedViewController.customVisibleViewController
} else if self is UIAlertController {
return nil
} else {
return self
}
}
}
extension UIApplication {
/// The top most view controller
static var topMostViewController: UIViewController? {
return UIApplication.shared.keyWindow?.rootViewController?.customVisibleViewController
}
}
现在您可以通过这种方式显示警报:
let alert = UIAlertController(title: "My Alert", message: "This is an alert.", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: "Default action"),
style: .default, handler: { _ in
NSLog("The \"OK\" alert occured.")
}))
UIApplication.topMostViewController?.present(alert, animated: true, completion: nil)
这是触发警报的代码。 使用 addAction,您可以添加可能的答案。
do {
try //some method call or something else
} catch {
let alert = UIAlertController(title: "There was an error while saving!", message: "Please try again", preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "I understand", style: .cancel, handler: nil))
}
您可以在此处找到更多信息: 如何显示警报
我解决了这个问题。 实际上,我所有的假设和问题都是错误的。
TL; DR storyboard 已损坏或损坏,当我从其中删除标签栏以以编程方式进行制作时。
这里是长版。 在进入这个麻烦之前,我有一个 storyboard 有两个视图和一个标签栏 controller。 它工作得很好。 有一次,我决定在应用程序启动期间做出选择,如果缺少默认值,请立即加载设置视图。 我发现,要做到这一点,我必须将标签栏向下移动到场景委托并将其从情节提要中删除。 我做到了,所以 storyboard 显示给没有链接的视图,我从场景委托实例化了选项卡栏。
奇怪的是,正在渲染的标签栏仍然显示之前在 storyboard 上设置的一些属性,即使该组件已被删除。
然后,你就知道问题所在了。 我的推理没有任何意义。 UITabBarController
不能显示任何警报。 警报只能在UIViewController上UIViewController
。 因此,继续尝试从标签栏发出警报是没有意义的。 这种错误的理解也导致我进行了错误的研究,报告了各种类似的问题(可能具有误导性)。
我终于做了一个反测试。 使用 storyboard 创建了一个全新的项目。 在 storyboard 上创建了两个视图,并在场景委托上定义了一个标签栏 controller。 它按预期工作。 我将每个视图链接到特定的UIViewController
。 在视图上创建了一个按钮,添加了IBAction
并且它起作用了。 然后,我在IBAction
中创建了警报,这一次,工作正常。 我以相同的代码结束,唯一不同的是我没有从 storyboard 中创建和删除标签栏。
我知道 storyboard 可能会损坏,而且我可能做到了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.