繁体   English   中英

使用 storyboard 和自定义 UITabBarController 显示警报

[英]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!")
    }
}

我开始认为我使用SceneDelegateAppDelegate的主要设置是错误的。 我发现的大多数以前的教程或线程似乎都无法编译,因为使用了已弃用的版本。

这是一种从任何呈现的视图 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不能显示任何警报。 警报只能在UIViewControllerUIViewController 因此,继续尝试从标签栏发出警报是没有意义的。 这种错误的理解也导致我进行了错误的研究,报告了各种类似的问题(可能具有误导性)。

我终于做了一个反测试。 使用 storyboard 创建了一个全新的项目。 在 storyboard 上创建了两个视图,并在场景委托上定义了一个标签栏 controller。 它按预期工作。 我将每个视图链接到特定的UIViewController 在视图上创建了一个按钮,添加了IBAction并且它起作用了。 然后,我在IBAction中创建了警报,这一次,工作正常。 我以相同的代码结束,唯一不同的是我没有从 storyboard 中创建和删除标签栏。

我知道 storyboard 可能会损坏,而且我可能做到了。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM