Получите верхний ViewController в iOS Swift
Я хочу реализовать отдельный class ErrorHandler, который отображает сообщения об ошибках для определенных событий. Поведение этого classа должно вызываться из разных других classов. При возникновении ошибки он будет иметь выход UIAlertView
. Дисплей этого AlertView должен ВСЕГДА быть на высоте. Поэтому, независимо от того, откуда возникает ошибка, верхний viewController должен отображать AlertMessage (например, при сбое асинхронного фонового процесса я хочу получить сообщение об ошибке, независимо от того, какой вид отображается на переднем плане).
Я нашел несколько gists, которые, кажется, решают мою проблему (см. Код ниже). Но вызов UIApplication.sharedApplication().keyWindow?.visibleViewController()
возвращает значение nil.
Расширение от сущности
- Как я могу справиться с дефолтом вывода @objc с помощью #selector () в Swift 4?
- Как использовать метод экземпляра как обратный вызов для функции, которая принимает только func или буквальное закрытие
- Swift - Пользовательский сеттер на свойстве
- Запретить увольнение UIAlertController
- Как изменить текстовое представление, отображаемое для типа в Swift?
extension UIWindow { func visibleViewController() -> UIViewController? { if let rootViewController: UIViewController = self.rootViewController { return UIWindow.getVisibleViewControllerFrom(rootViewController) } return nil } class func getVisibleViewControllerFrom(vc:UIViewController) -> UIViewController { if vc.isKindOfClass(UINavigationController.self) { let navigationController = vc as! UINavigationController return UIWindow.getVisibleViewControllerFrom( navigationController.visibleViewController) } else if vc.isKindOfClass(UITabBarController.self) { let tabBarController = vc as! UITabBarController return UIWindow.getVisibleViewControllerFrom(tabBarController.selectedViewController!) } else { if let presentedViewController = vc.presentedViewController { return UIWindow.getVisibleViewControllerFrom(presentedViewController.presentedViewController!) } else { return vc; } } } }
- Значение типа «StorageMetadata» не имеет имени пользователя downloadURL '
- Как переместить врага в сторону движущегося игрока?
- Ошибка сегментации компилятора Swift при построении
- Синхронная внутренняя связь JavaScript с WKWebView
- Какой протокол должен быть принят типом для общей функции, чтобы использовать любой тип номера в качестве аргумента в Swift?
- Оператор равенства Swift для вложенных массивов
- Меню боковой панели слайдов IOS 8 Swift
- Как управлять расстоянием между строками в UILabel
Amit89 поднял путь к решению. Вы должны вызвать свойство .window AppDelegate. Поэтому я изменил код Swift по приведенной ниже ссылке, чтобы работать как можно ближе к самому верхнему ViewController. Убедитесь, что представление уже находится в иерархии представлений. Поэтому этот метод нельзя вызывать из .viewDidLoad
Расширение, чтобы найти самый верхний ViewController *
extension UIApplication { class func topViewController(base: UIViewController? = (UIApplication.sharedApplication().delegate as! AppDelegate).window?.rootViewController) -> UIViewController? { if let nav = base as? UINavigationController { return topViewController(base: nav.visibleViewController) } if let tab = base as? UITabBarController { if let selected = tab.selectedViewController { return topViewController(base: selected) } } if let presented = base?.presentedViewController { return topViewController(base: presented) } return base } }
Этот код был создан пользователем GitHub Yonat в комментарии к эквиваленту objectiveC. Я только изменил биты кода, чтобы заставить его работать без свойства .keyWindow
Вы пробовали это по той же ссылке?
let appDelegate = UIApplication.sharedApplication().delegate as! MYAppDelegate//Your app delegate class name. extension UIApplication { class func topViewController(base: UIViewController? = appDelegate.window!.rootViewController) -> UIViewController? { if let nav = base as? UINavigationController { return topViewController(base: nav.visibleViewController) } if let tab = base as? UITabBarController { if let selected = tab.selectedViewController { return topViewController(base: selected) } } if let presented = base?.presentedViewController { return topViewController(base: presented) } return base } }