线程安全的方式来获得当前显示视图控制器

问题描述:

目前我使用这种方法来获得当前视图控制器:线程安全的方式来获得当前显示视图控制器

func topMostContoller()-> UIViewController?{ 
    if !Thread.current.isMainThread{ 
     logError(message: "ACCESSING TOP MOST CONTROLLER OUTSIDE OF MAIN THREAD") 
     return nil 
    } 

    let topMostVC:UIViewController = UIApplication.shared.keyWindow!.rootViewController! 
    return topVCWithRootVC(topMostVC) 
} 

该方法经过开始在RootViewController的视图控制器的层次结构,直到它到达顶部。

func topVCWithRootVC(_ rootVC:UIViewController)->UIViewController?{ 
    if rootVC is UITabBarController{ 
     let tabBarController:UITabBarController = rootVC as! UITabBarController 
     if let selectVC = tabBarController.selectedViewController{ 
      return topVCWithRootVC(selectVC) 
     }else{ 
      return nil 
     } 
    }else if rootVC.presentedViewController != nil{ 
     if let presentedViewController = rootVC.presentedViewController! as UIViewController!{ 
      return topVCWithRootVC(presentedViewController) 
     }else{ 
      return nil 
     } 
    } else { 
     return rootVC 
    } 
} 

这个问题在topMostController,因为它使用UIApplication.shared.keyWindowUIApplication.shared.keyWindow.rootViewController不应该在后台线程中使用。而我得到这些警告:

runtime: UI API called from background thread: UIWindow.rootViewController must be used from main thread only

runtime: UI API called from background thread: UIApplication.keyWindow must be used from main thread only

所以我的问题是。是否有线程安全的方式来访问当前显示的视图控制器?

+0

添加''回报在'logError ...'之后的'nil'。但正确的解决方案是修复你的代码,所以你只能从主队列中调用'topMostController'。 – rmaddy

从主线程访问会适合您的需求吗?

func getTopThreadSafe(completion: @escaping(UIViewController?) -> Void) { 
    DispatchQueue.main.async { 
     let topMostVC: UIViewController = UIApplication.shared.keyWindow?.rootViewController? 
     completion(topMostVC) 
    } 
} 

这样可以得到一点点混乱,因为它是一个异步方法,但我的直觉告诉我,this'd是,不管你是最多最安全的选择,以:)

+0

感谢您的回答。是的,我已经做了类似的事情,这是可能的。如果有合理的解决方案,我想要做的就是避免大规模重构。但看起来我只需要做这件事。我会让问题坐得更久一些。虽然看起来并不乐观。 – boidkan

+0

绝对好运。 – MQLN