Попередження: Спробуйте представити * на *, чий вигляд відсутній у ієрархії вікна - швидко


83

Я намагаюся представити a, ViewController якщо в моделі даних є якісь збережені дані. Але я отримую таку помилку:

Попередження: Спробуйте представити * на *, чий вигляд відсутній у ієрархії вікна "

Відповідний код:

override func viewDidLoad() {
    super.viewDidLoad()
    loginButton.backgroundColor = UIColor.orangeColor()

    var request = NSFetchRequest(entityName: "UserData")
    request.returnsObjectsAsFaults = false

    var appDel:AppDelegate = (UIApplication.sharedApplication().delegate as AppDelegate)
    var context:NSManagedObjectContext = appDel.managedObjectContext!

    var results:NSArray = context.executeFetchRequest(request, error: nil)!

    if(results.count <= 0){
        print("Inga resultat")
    } else {
        print("SWITCH VIEW PLOX")
        let internVC = self.storyboard?.instantiateViewControllerWithIdentifier("internVC") as internViewController
        self.presentViewController(internVC, animated: true, completion: nil)
    }
}

Я без успіху перепробував різні рішення, знайдені за допомогою Google.


Ви підключили ваш ViewController в Storyboard? Ви використовуєте тут NavigationController?
derdida

Що ви маєте на увазі, якщо я підключився до свого ViewControllerрозкадрування? Я не використовую NavigationController@derdida
Nils Wasell

Спробуйте: self.addChildViewController (childController: UIViewController) у ViewDidLoad
derdida

Це генерує помилку. Він очікує імені члена або виклику конструктора після "type name" ( UIViewControllerЧастина). @derdida
Nils Wasell

Де ви це написали? У ViewDidLoad вашого MainViewController?
derdida

Відповіді:


126

На даний момент у вашому коді подання контролера перегляду було лише створено, але не додано до жодної ієрархії подання. Якщо ви хочете якомога швидше представити з цього контролера подання, ви повинні зробити це, viewDidAppearщоб бути найбезпечнішим.


2
Якщо я поміщу його в viewDidAppear, тоді, коли я відхилю представленийViewController, він знову викличе метод viewDidAppear і знову представить viewController. умовне твердження?
Puneet

2
Я б сказав, що спроба представити інший модальний тип права, коли з’являється екран, - це дивна поведінка, з якої починається, тому державний бул навряд чи є найгіршим рішенням. У той же час, подумайте про першопричину, яка вам потрібна для відображення модального способу, і подивіться, чи можете ви отримати доступ до цієї інформації.
Acey

2
Якщо ви зробите це у viewWillAppear, у вас виникне ситуація, коли вона починає презентацію, коли ви починаєте презентацію. Альтернативним варіантом може бути розміщення його у viewWillAppear, але використання властивості переходуCoordinator, нового в iOS 8, для додавання коду в завершенні переходу. Більше інформації можна знайти тут developer.apple.com/library/prerelease/ios/documentation/UIKit/…
Acey

36

У цілі c: Це вирішило мою проблему при поданні контролера перегляду поверх mpmovieplayer

- (UIViewController*) topMostController
{
    UIViewController *topController = [UIApplication sharedApplication].keyWindow.rootViewController;

    while (topController.presentedViewController) {
        topController = topController.presentedViewController;
    }

    return topController;
}

34

Стрімкий 3

У мене це постійно з’являлося як новачок, і я виявив, що присутні завантажує модальні подання, які можна відхилити, але перехід на кореневий контролер найкраще, якщо вам не потрібно показувати модальний.

Я цим користувався

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let vc  = storyboard?.instantiateViewController(withIdentifier: "MainAppStoryboard") as! TabbarController
present(vc, animated: false, completion: nil)

Використовуючи це замість мого tabController:

let storyboard = UIStoryboard(name: "Main", bundle: nil)
let view = storyboard.instantiateViewController(withIdentifier: "MainAppStoryboard") as UIViewController
let appDelegate = UIApplication.shared.delegate as! AppDelegate
//show window
appDelegate.window?.rootViewController = view

Просто налаштуйтеся на контролер перегляду, якщо вам потрібно переключитися між кількома екранами розкадровки.


16

Стрімкий 3.

Викличте цю функцію, щоб отримати найвищий контролер перегляду, а потім присутні цей контролер перегляду.

func topMostController() -> UIViewController {
    var topController: UIViewController = UIApplication.shared.keyWindow!.rootViewController!
        while (topController.presentedViewController != nil) {
            topController = topController.presentedViewController!
        }
        return topController
    }

Використання:

let topVC = topMostController()
let vcToPresent = self.storyboard!.instantiateViewController(withIdentifier: "YourVCStoryboardID") as! YourViewController
topVC.present(vcToPresent, animated: true, completion: nil)

1
Подяка @Jacob Davis за це! Я використав його для подання alertController, тому що отримав попередження: Спроба подати ....
Гері Манстед,

Це дуже корисно. дещо, що я отримую, представляючи контролер, але екран не з'являється. раптом його звільняють. Будь-який інший код потрібно реалізувати? будь ласка, запропонуйте
Seethalakshmi_user8943692

13

для SWIFT

func topMostController() -> UIViewController {
    var topController: UIViewController = UIApplication.sharedApplication().keyWindow!.rootViewController!
    while (topController.presentedViewController != nil) {
        topController = topController.presentedViewController!
    }
    return topController
}

1
Дякую! Це єдине, що вирішило цю помилку для мене. Я намагався представити модальний ВК з функції, яка запускається розпізнавачем жестів, після того, як подання повністю завантажилось (у Xcode 8 / iOS 10). Дивно, але topControllerповернена цією функцією є точно такою ж VC, як і selfпри спробі безпосереднього представлення за допомогою self.presentViewController(myModalVC), але помилки ієрархії подання не виникає, коли я передаю представлений VC за допомогою вашої функції.
Наталія

13

Вам просто потрібно виконати селектор із затримкою - (працює 0 секунд).

override func viewDidLoad() {
    super.viewDidLoad()
    perform(#selector(presentExampleController), with: nil, afterDelay: 0)
}

@objc private func presentExampleController() {
    let exampleStoryboard = UIStoryboard(named: "example", bundle: nil)
    let exampleVC = storyboard.instantiateViewController(withIdentifier: "ExampleVC") as! ExampleVC
    present(exampleVC, animated: true) 
}

Дуже дякую. Я застряг у цій проблемі більше години.
Реза

Дякую ... @objc func presentExampleController ()
Вільям Чой

Я думаю, що це дивовижна відповідь!
mazend

Це хак (який може працювати зараз), але підготує вас до чогось, що зламається в несподіваних випадках.
Вільям Гранд,

6

Стрімкий 4

func topMostController() -> UIViewController {
    var topController: UIViewController = UIApplication.shared.keyWindow!.rootViewController!
    while (topController.presentedViewController != nil) {
        topController = topController.presentedViewController!
    }
    return topController
}

1
Пояснення та приклад були б корисними @AllenWixted
Pérez Beltré

2

Для швидкої версії 3.0 і вище

public static func getTopViewController() -> UIViewController?{
if var topController = UIApplication.shared.keyWindow?.rootViewController
{
  while (topController.presentedViewController != nil)
  {
    topController = topController.presentedViewController!
  }
  return topController
}
return nil}

2

Я отримав цю помилку під час презентації контролера після того, як користувач відкрив deeplink. Я знаю, що це не найкраще рішення, але якщо у вас короткі терміни, ось швидке виправлення - просто оберніть свій код у asyncAfter:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.7, execute: { [weak self] in
                                navigationController.present(signInCoordinator.baseController, animated: animated, completion: completion)
                            })

Це дасть час для дзвінка вашого контролера, що представляє viewDidAppear.


1
let storyboard = UIStoryboard(name: "test", bundle: nil)
let vc = storyboard.instantiateViewController(withIdentifier: "teststoryboard") as UIViewController
UIApplication.shared.keyWindow?.rootViewController?.present(vc, animated: true, completion: nil)

Здавалося, це спрацювало, щоб переконатися, що це найкращий вид.

Я отримував повідомлення про помилку

Попередження: Спробуйте представити myapp.testController: 0x7fdd01703990 на myapp.testController: 0x7fdd01703690, вигляд якого відсутній у ієрархії вікна!

Сподіваюся, це швидко допоможе іншим


1

Я спробував стільки схвалень! єдине корисне:

if var topController = UIApplication.shared.keyWindow?.rootViewController
{
  while (topController.presentedViewController != nil)
  {
    topController = topController.presentedViewController!
  }
}

1

Вся реалізація для topViewController тут не повністю підтримує випадки, коли у вас є, UINavigationControllerабо UITabBarControllerдля цих двох вам потрібна дещо інша обробка:

Для UITabBarControllerі UINavigationControllerвам потрібна інша реалізація.

Ось код, який я використовую для отримання topMostViewController:

protocol TopUIViewController {
    func topUIViewController() -> UIViewController?
}

extension UIWindow : TopUIViewController {
    func topUIViewController() -> UIViewController? {
        if let rootViewController = self.rootViewController {
            return self.recursiveTopUIViewController(from: rootViewController)
        }

        return nil
    }

    private func recursiveTopUIViewController(from: UIViewController?) -> UIViewController? {
        if let topVC = from?.topUIViewController() { return recursiveTopUIViewController(from: topVC) ?? from }
        return from
    }
}

extension UIViewController : TopUIViewController {
    @objc open func topUIViewController() -> UIViewController? {
        return self.presentedViewController
    }
}

extension UINavigationController {
    override open func topUIViewController() -> UIViewController? {
        return self.visibleViewController
    }
}

extension UITabBarController {
    override open func topUIViewController() -> UIViewController? {
        return self.selectedViewController ?? presentedViewController
    }
}

1

Свіфт метод та надайте демо.

func topMostController() -> UIViewController {
    var topController: UIViewController = UIApplication.sharedApplication().keyWindow!.rootViewController!
    while (topController.presentedViewController != nil) {
        topController = topController.presentedViewController!
    }
    return topController
}

func demo() {
    let vc = ViewController()
    let nav = UINavigationController.init(rootViewController: vc)
    topMostController().present(nav, animated: true, completion: nil)
}

1

Використання основного потоку для презентації та відхилення контролера подання спрацювало для мене.

DispatchQueue.main.async { self.present(viewController, animated: true, completion: nil) }

0

Замість того, щоб знайти контролер вигляду зверху, можна використовувати

viewController.modalPresentationStyle = UIModalPresentationStyle.currentContext

Де viewController - це контролер, який ви хочете презентувати. Це корисно, коли в ієрархії є різні види подань, такі як TabBar, NavBar, хоча інші здаються правильними, але більш хитрими

Інший стиль презентації можна знайти на apple doc


0

Попередні відповіді стосуються ситуації, коли контролер подання, який повинен представляти подання 1) ще не доданий до ієрархії подання, або 2) не є контролером подання зверху.
Інша можливість полягає в тому, що попередження повинно бути подане, тоді як інше попередження вже подане, а ще не відхилено.


0

Свіфт 5.1 :

let storyboard = UIStoryboard.init(name: "Main", bundle: Bundle.main)
let mainViewController = storyboard.instantiateViewController(withIdentifier: "ID")
let appDeleg = UIApplication.shared.delegate as! AppDelegate
let root = appDeleg.window?.rootViewController as! UINavigationController
root.pushViewController(mainViewController, animated: true)
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.