Предупреждение: Попытка представить * на *, который уже присутствует (null)

Это мое первое приложение для iOS.

Итак, у меня есть UIVIewController с UITableView, где я интегрировал UISearchBar и UISearchController, чтобы отфильтровать TableCells для отображения

override func viewDidLoad() {
    menuBar.delegate = self
    table.dataSource = self
    table.delegate = self
    let nib = UINib(nibName: "ItemCellTableViewCell", bundle: nil)
    table.registerNib(nib, forCellReuseIdentifier: "Cell")

    let searchButton = UIBarButtonItem(barButtonSystemItem: .Search, target: self, action: "search:")
    menuBar.topItem?.leftBarButtonItem = searchButton
    self.resultSearchController = ({
        let controller = UISearchController(searchResultsController: nil)
        controller.searchResultsUpdater = self
        controller.dimsBackgroundDuringPresentation = false
        return controller
    })()
    self.table.reloadData()
}

Я также использую модальный переход, чтобы открыть ViewController элемента, где я покажу детали элемента.

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    self.index = indexPath.row
    self.performSegueWithIdentifier("ItemDetailFromHome", sender: self)
}

override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
    if (segue.identifier == "ItemDetailFromHome") {
        let settingsVC = segue.destinationViewController as! ItemDetailViewController
        settingsVC.parent = self
        if self.isSearching == true  && self.searchText != nil && self.searchText != ""  {
            settingsVC.item = self.filteredItems[self.index!]
        } else {
            settingsVC.item = self.items[self.index!]
        }

    }
}

Это работает нормально, пока я не попытаюсь отобразить ItemDetailViewController для фильтруемого элемента (через UISearchController).

У меня такое сообщение:

Warning: Attempt to present <ItemDetailViewController: *>  on <HomeViewController: *> which is already presenting (null)

Каждый раз я перехожу к функции ItemDetailViewController.viewDidLoad(), но после этого, когда поиск активирован, у меня появляется предыдущая ошибка.

Любая идея ? Я попытался использовать следующую асинхронную отправку, но безуспешно

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    self.index = indexPath.row
    dispatch_async(dispatch_get_main_queue(), { () -> Void in
        self.performSegueWithIdentifier("ItemDetailFromHome", sender: self)
    })
}

person Splendf    schedule 21.09.2015    source источник
comment
если вы устанавливаете ItemDetailFromHome из контроллера tableview, нет необходимости вызывать self.performSegueWithIdentifier (ItemDetailFromHome, sender: self), если выбрана строка по пути индекса   -  person Johnykutty    schedule 21.09.2015
comment
Фактически ItemDetailViewController будет представлением, используемым несколькими segue / viewController (объединенными).   -  person Splendf    schedule 21.09.2015
comment
Отлично, и как я могу это сделать? в cellForRowAtIndexPath? Я только что видел примеры с performSegue   -  person Splendf    schedule 21.09.2015
comment
Если вы добавили переход из ячейки tableview в раскадровку, тогда не нужно писать self.performSegue ... свой код. Если вы добавили переход из контроллера представления, это необходимо сделать   -  person Johnykutty    schedule 03.01.2017
comment
@Johnykutty Спасибо! Когда я проводил рефакторинг проекта, я обнаружил, что столкнулся с этой самой проблемой. Спасибо, что разместили такое простое решение.   -  person Adrian    schedule 08.03.2017


Ответы (17)


Я нашел решение.

Я добавил следующий код в HomeViewController.viewDidLoad, и он работает!

definesPresentationContext = true
person Splendf    schedule 27.09.2015
comment
@Shahar, это работает, потому что definesPresentationContext в основном говорит, что я являюсь контроллером представления, который будет использоваться, когда вы представляете другой контроллер модального представления. В противном случае он будет перемещаться вверх по иерархии представлений, чтобы найти, у кого когда-либо установлено definesPresentationContext значение true, и использовать его для представления, и он, возможно, уже представляет ... - person cohen72; 22.10.2017
comment
по какой-то причине это сработало только после встраивания viewcontroller в uinavigationcontroller - person Crashalot; 23.11.2017
comment
Мое приложение отлично работало на iOS 10 и 11, затем я протестировал его на iPhone 4 и начал показывать эту ошибку. Это решение сработало как шарм. Кстати, вы также можете установить definePresentationContext, выбрав View Controller в редакторе раскадровки и установив флажок Defines context. - person Felipe Ferri; 11.01.2018
comment
наконец-то решение проблемы, которая меня долго беспокоила. Спасибо, сэр. - person iDoc; 03.11.2018
comment
Я считаю это уловкой, потому что это лечит симптом, а не причину. - person Mojo66; 28.05.2020
comment
это взлом, потому что успех зависит от иерархии viewControllers - person Blazej SLEBODA; 31.07.2020

В моем случае я обнаружил, что мой код для представления нового viewController (a UIAlertController) вызывался дважды.

Проверьте это, прежде чем возиться с definesPresentationContext.

person grahamparks    schedule 03.11.2016
comment
Это кажется почти глупым, но я уверен, что в подавляющем большинстве случаев это будет правильный ответ. Конечно, я нашел второй звонок ... - person the_dude_abides; 16.02.2017
comment
Да, в некоторых случаях нам нужно проверить presentedViewController перед представлением - person onmyway133; 05.02.2018
comment
В моем случае он не вызывался дважды, но я вызвал present () внутри shouldPerformSegue () и забыл вернуть false, чтобы не допустить, чтобы раскадровка тоже что-то представляла. - person randomcontrol; 29.09.2019
comment
Мы будем глючить. Мы также нашли второй звонок present. - person Aaron; 19.12.2020

В моем случае я слишком рано попытался показать новый UIViewController перед закрытием предыдущего. Проблема решилась звонком с небольшой задержкой:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
     self.callMethod()
}
person Pavel Kataykin    schedule 10.09.2018
comment
Я действительно не рекомендую использовать случайную задержку в 0,3 секунды. Попробуйте найти правильный метод, после которого вы можете представить (viewDidAppear) вместо того, чтобы надеяться, что иерархия будет готова через 0,3 секунды - person Allison; 01.07.2019
comment
Этот ответ должен быть отвергнут как уродливый взлом. - person Mojo66; 28.05.2020
comment
В моем случае это позволило мне увидеть второй контроллер представления, который был добавлен по ошибке. Его можно использовать не как решение, а как средство отладки. - person Rostyslav Druzhchenko; 05.02.2021

У меня возникла та же проблема, когда я попытался представить виртуальный канал, который вызывается внутри SideMenu (jonkykong).

сначала я попробовал внутри SideMenu, и я вызвал его из делегата в MainVC, у обоих была одна и та же проблема.

Решение: сначала закройте SideMenu и представьте новый VC после того, как он будет работать идеально!

person Lahiru Pinto    schedule 31.05.2019

Проблема для меня в том, что я представлял два модальных окна, и я должен отклонить оба, а затем выполнить некоторый код в родительском окне ... и затем у меня есть эта ошибка ... Я решил, что установил этот код в отклонении последнего модальный представлен:

self.dismiss(animated: true, completion: {
                self.delegate?.callingDelegate()
            })

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

person Hiram Elguezabal    schedule 04.06.2019

Это случилось со мной на нашем проекте. Я представлял наш вход / выход ViewController как всплывающее окно. Но всякий раз, когда я пытался снова выйти из системы и снова отобразить всплывающее окно, я выходил из системы на моей консоли:

Warning: Attempt to present UIViewController on <MY_HOME_VIEW_CONTROLLER> which is already presenting (null)

Я предполагаю, что всплывающее окно все еще удерживалось моим ViewController, хотя его не было видно.

Однако вы пытаетесь отобразить новый ViewController, следующий код, который я использовал для решения проблемы, должен сработать для вас:

func showLoginForm() {

    // Dismiss the Old
    if let presented = self.presentedViewController {
        presented.removeFromParentViewController()
    }

    // Present the New
    let storyboard = UIStoryboard(name: "MPTLogin", bundle: Bundle(for: MPTLogin.self))
    let loginVC = storyboard.instantiateViewController(withIdentifier: "LogInViewController") as? MPTLogInViewController
    let loginNav = MPTLoginNav(rootViewController: loginVC!)
    loginNav.modalPresentationStyle = .pageSheet;
    self.present(loginNav, animated: true, completion: nil)
}
person Brandon A    schedule 17.01.2017
comment
Моя проблема была очень похожей. Оказалось, что я слишком внимательно следил за призывом уволить один контроллер представления с призывом представить другой. Заблуждение заключалось в том, что он действительно работал нормально в девяти случаях из десяти! - person Wade; 22.05.2018

Что сработало для меня, так это добавить представление предупреждения в основной поток.

DispatchQueue.main.async {
   self.present(alert, animated: true)
}

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

person Chris Herbst    schedule 14.12.2019

Я столкнулся с той же проблемой. Я сделал следующее: конструктор интерфейсов выбрал мой сегмент. Его тип был «Присутствовать модально», а его представление было «В текущем контексте».

я изменил презентацию на «По умолчанию», и тогда это сработало для меня.

person Prasanna Kumar    schedule 14.01.2016

В моем случае я пытался представить UIAlertController в какой-то момент времени существования приложения после использования UISearchController в том же UINavigationController.

Я неправильно использовал UISearchController и забыл установить searchController.isActive = false перед увольнением. Позже в приложении я попытался представить предупреждение, но контроллер поиска, хотя и не был виден в то время, все еще контролировал контекст презентации.

person Clay Ellis    schedule 29.01.2018
comment
Так рада встретить ваш ответ; ломал мне голову, пытаясь понять это, и мой тоже оказался UISearchController. - person James Toomey; 28.06.2018
comment
@JamesToomey рад, что смог помочь! Я потратил слишком много времени на то, чтобы сломать себя, прежде чем осознал, что происходит ... - person Clay Ellis; 02.07.2018
comment
Если вы боретесь с uisearchcontroller, ЭТО - ответ! - person Carioni; 27.10.2018

Моя проблема заключалась в том, что (в моем координаторе) я представил VC на VC, а затем, когда я хотел представить следующий VC (третий), представил третий VC из первого, что, очевидно, создает проблему which is already presenting. убедитесь, что вы представляете третий из второго VC.

secondVC.present(thirdVC, animated: true, completion: nil)
person Mehrdad    schedule 23.05.2020

Основываясь на ответе Mehrdad: сначала мне пришлось проверить, активен ли контроллер поиска (если пользователь в данный момент ищет) :

if self.searchController.isActive {
    self.searchController.present(alert, animated: true, completion: nil)
} else {
    self.present(alert, animated: true, completion: nil)
}

где alert - это контроллер представления для модального представления.

person smörkex    schedule 24.11.2020
comment
Это была моя проблема. Я всегда представлял новый контроллер представления (в моем случае PHPickerViewController) непосредственно из контроллера представления приложения, даже если контроллер поиска был активен. Я закодировал исправление путем вызова self.navigationController! .VisibleViewController! .Present. - person xirix; 28.04.2021

Это то, что в конечном итоге сработало для меня, поскольку в моем проекте не было NavigationVC, а вместо этого были отдельные отдельные VC. как файлы xib

Этот код вызвал ошибку:

present(alertVC, animated: true, completion: nil)

Этот код исправил ошибку:

 if presentedViewController == nil{
        navigationController?.present(alertVC, animated: true, completion: nil)
    }
person KarmaDeli    schedule 19.02.2018

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

Итак, я переместил новый текущий код VC в часть моего предупреждения, например:

    func showSuccessfullSignupAndGoToMainView(){

    let alert = UIAlertController(title: "Alert", message: "Sign up was successfull.", preferredStyle: .alert)
    alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { action in
        switch action.style{
        case .default:
            // Goto Main Page to show businesses
            let mainStoryboard = UIStoryboard(name: "Main", bundle: Bundle.main)
            let vc : MainViewController = mainStoryboard.instantiateViewController(withIdentifier: "MainViewController") as! MainViewController
            self.present(vc, animated: false, completion: nil)

        case .cancel:
            print("cancel")

        case .destructive:
            print("destructive")

        }}))
    self.present(alert, animated: true, completion: nil)
}
person Iman    schedule 04.02.2019

Моя проблема заключалась в том, что я пытался представить предупреждение из представления, которое не было наверху. Убедитесь, что вы представляете из самого верхнего viewController.

person powertoold    schedule 07.10.2019

В моем случае это была проблема кнопки, которая была продублирована в Interface Builder. К исходной кнопке был прикреплен обработчик ретуши, который также представлял модальный вид. Когда я затем прикрепил обработчик ретуши к скопированной кнопке, я забыл удалить скопированный обработчик из оригинала, что привело к срабатыванию обоих обработчиков и созданию предупреждения.

person Mads Mobæk    schedule 15.10.2019

Скорее всего, у вас есть кнопка Search, подключенная напрямую к другому контроллеру представления с помощью segue и, которые вы вызываете performSegueWithIdentifier. Таким образом, вы открываете его дважды, что приводит к ошибке, говорящей о том, что вы уже представляете.

Так что не вызывайте performSegueWithIdentifier, и это должно помочь.

person Rydell    schedule 13.08.2020

Убедитесь, что вы отклонили предыдущий, прежде чем предлагать новый!

person Mahdi Giveie    schedule 21.02.2021