簡體   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