在iOS中获取顶部ViewController Swift

问题描述:

我想实现一个单独的ErrorHandler类,它在某些事件上显示错误消息。这个类的行为应该从不同的其他类中调用。 发生错误时,它将有一个UIAlertView作为输出。 此AlertView的显示应始终处于顶端。因此无论从何处引发错误,最顶层的viewController都应该显示AlertMessage(例如,当异步后台进程失败时,无论View在前台显示什么内容,都需要一条错误消息)。在iOS中获取顶部ViewController Swift

我发现了几个似乎解决了我的问题的要点(请参阅下面的代码)。 但调用UIApplication.sharedApplication().keyWindow?.visibleViewController()确实返回一个零值。从要点

扩展

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; 
    } 
} 
} 
} 
+0

对于你来说什么程度都可以,请*你*分享你是githHub或其他地方的ErrorHandler类? – Honey

Amit89带来了一种解决方案。您必须致电AppDelegate的.window属性。 所以我改变了以下链接中的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用户Yonatcomment到的ObjectiveC等同。我只是改变了代码的位来让它在没有.keyWindow属性的情况下工作

+9

我正在使用你的扩展来查找最顶层的ViewController,但是如果出现警告,上面的代码给出了UIAlertController。如何获得UIAlertController下的顶部视图控制器? – Luda

你是从同一个链接试试这个?

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 
    } 
} 
+0

是的,我做了:_fatal错误:意外地发现零,而解包一个可选值_ 问题是,'UIApplication.sharedApplication().keyWindow?.rootViewController)'返回nil – gutenmorgenuhu

+0

而不是关键窗口使用应用程序委托类的窗口属性。 – Amit89

+0

如果有帮助,应该被接受为正确答案。 – Amit89