2017-10-12 1 views
1

Actuellement, j'utiliser cette méthode pour obtenir le contrôleur de vue actuel:fil de manière sûre pour obtenir contrôleur de vue affichée

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) 
} 

Cette méthode passe par la hiérarchie des contrôleurs de vue à partir de la RootViewController jusqu'à ce qu'il atteigne le sommet .

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

Cette question est en topMostController car il utilise UIApplication.shared.keyWindow et UIApplication.shared.keyWindow.rootViewController qui ne devrait pas être utilisé dans un thread d'arrière-plan. Et je reçois ces avertissements:

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

Alors ma question est. Y a-t-il un moyen sûr d'accéder au contrôleur de vue actuellement affiché?

+0

Ajouter '' retour nil' juste après 'logError ...'. Mais la bonne solution consiste à corriger votre code de sorte que vous n'appelez 'topMostController' que depuis la file d'attente principale. – rmaddy

Répondre

0

L'accès depuis le fil principal répondra à vos besoins?

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

cela peut devenir un peu déroutant, car il est une méthode asynchrone, mais mon instinct me dit que this'd être l'option la plus sûre avec tout ce que vous êtes à :)

+0

Merci pour la réponse. Oui, j'ai fait quelque chose de semblable à ceci où c'est possible. Ce que je voulais faire, c'était éviter le refactoring de masse s'il y avait une solution raisonnable. Mais il me semble que je vais devoir faire quelque chose. Je vais laisser la question reposer un peu plus longtemps. Ne pas avoir l'air optimiste. – boidkan

+0

Absolument, bonne chance. – MQLN