Warning: Attempt to present * on * which is already presenting (null)
Asked Answered
S

19

80

This is my first application for iOS.

So I have a UIVIewController with a UITableView where I have integrated a UISearchBar and a UISearchController in order to filter TableCells to display

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

I am using also a modal segue in order to open the element's ViewController where I will display details of the element.

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

    }
}

That works fine until I try to display the ItemDetailViewController for a filtered element (through the UISearchController).

I have the following message :

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

At every time I am going to the ItemDetailViewController.viewDidLoad() function but after that when the search is activated I have the previous error.

Any idea ? I have tried to use the following async dispatch but without success

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    self.index = indexPath.row
    dispatch_async(dispatch_get_main_queue(), { () -> Void in
        self.performSegueWithIdentifier("ItemDetailFromHome", sender: self)
    })
}
Stagehand answered 21/9, 2015 at 13:32 Comment(5)
if you are setting ItemDetailFromHome from the tableview controller no need to call self.performSegueWithIdentifier("ItemDetailFromHome", sender: self) in did select row at index pathPropertius
In fact the ItemDetailViewController will be a view used by several segue/viewController (mutualized).Stagehand
Great, and how I can do that ? in cellForRowAtIndexPath ? I have just seen examples with performSegueStagehand
If you have added the segue from tableview cell in storyboard, then no need to write self.performSegue... your code. If you have added segue from the view controller, its needed to do soPropertius
@Propertius Thank you! When I was refactoring a project, I discovered I had this very problem. Thank you for posting such a simple solution.Hirz
S
85

I have found out a solution.

I have add the following code in HomeViewController.viewDidLoad and that works !

definesPresentationContext = true
Stagehand answered 27/9, 2015 at 10:37 Comment(6)
@Shahar this works because definesPresentationContext is basically saying "I'm the view controller to be use when you presenting another modal view controller". Otherwise, it will travel up the view hierarchy to find who ever does have definesPresentationContext set to true and use that one to present, and he might already be presenting ...Ambidexter
for some reason, this only worked after embedding the viewcontroller in a uinavigationcontrollerSonics
My app was working perfectly on iOS 10 and 11, then I tested it on an iPhone 4 and started showing this error. This solution worked as a charm. By the way, you can also set definesPresentationContext selecting the View Controller on the Storyboard Editor and enabling the checkbox "Defines context".Propman
finally a solution to a problem that bugged me a long time. thank you, sir.Nedneda
I consider this a hack because it is curing the symptom and not the cause.Gallium
this is a hack because the success depends on a viewControllers hierarchyOverexcite
A
37

In my case, I found my code to present the new viewController (a UIAlertController) was being called twice.

Check this before messing about with definesPresentationContext.

Astatine answered 3/11, 2016 at 21:58 Comment(4)
Seems almost silly, but I bet in a vast majority of cases this will be the correct answer. Sure enough I found a 2nd call...Querida
Yeah, in some cases we need to check for presentedViewController before presentingDeformity
In my case it didn't get called twice but I called present() inside shouldPerformSegue() and forgot to return false to prevent the storyboard segue to present something too.Hyades
We'll I'll be buggered. We found a second call to present, as well.Elisavetpol
C
14

In my case, I tried too early to show the new UIViewController before closing the previous one. The problem was solved through a call with a slight delay:

DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
     self.callMethod()
}
Cimbalom answered 10/9, 2018 at 19:42 Comment(3)
I really don't recommend using a random 0.3 second delay. Try and find the correct method after which you can present (viewDidAppear) instead of hoping that the hierarchy is ready after 0.3 secondsHaney
This answer should be downvoted for being an ugly hack.Gallium
In my case it allowed me to see the second view controller that presenting has been added by a mistake. It might be used not as a solution but as a debug tool.Crotchet
K
8

The problem for me is that I was presenting two modals and I have to dismiss both and then execute some code in the parent window ... and then I have this error... I solved it seting this code in the dismiss o the last modal presented:

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

in other words instead of just dismiss two times .. in the completion block of the first dismiss call delegate that will execute the second dismiss.

Kornegay answered 4/6, 2019 at 15:36 Comment(0)
T
8

What worked for me was to add the presentation of the alert to the main thread.

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

The presentation of the current viewController was not complete. By adding the alert to the main thread it can wait for the viewController's presentation to complete before attempting to present.

Trace answered 14/12, 2019 at 15:12 Comment(1)
This was my issue! I was on a background thread and forgot.Chewning
S
5

I got the same issue when i tried to present a VC which called inside the SideMenu(jonkykong).

first i tried inside the SideMenu and i called it from the delegate to the MainVC both had the same issue.

Solution: dismiss the SideMenu first and present the new VC after will works perfectly!.

Sitter answered 31/5, 2019 at 14:20 Comment(0)
S
4

This happened with me on our project. I was presenting our log in/log out ViewController as a pop-over. But whenever I tried to log back out again and display the pop-over again, I was getting this logged out in my console:

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

My guess is that the pop-over was still being held by my ViewController even though it was not visible.

However you are attempting to display the new ViewController, the following code I used to solve the issue should work for you:

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)
}
Simulate answered 17/1, 2017 at 19:36 Comment(1)
My problem was very similar. It turned out I was following a call to dismiss one view controller too closely with a call to present another. The misleading part was that it would actually work fine nine times out of ten!Syncom
D
3

Building on Mehrdad's answer: I had to first check if the search controller is active (if the user is currently searching):

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

where alert is the view controller to present modally.

Drumfish answered 24/11, 2020 at 4:34 Comment(1)
This was exactly my problem. I was always presenting the new view controller (PHPickerViewController in my case) directly from the app view controller, even if a search controller was active. The way I coded the fix was to call self.navigationController!.visibleViewController!.present.Heterotrophic
I
2

I faced the same kind of problem What I did is from Interface builder selected my segue Its kind was "Present Modally" and its presentation was "Over current context"

i changed the presentation to "Default", and then it worked for me.

Infatuated answered 14/1, 2016 at 6:17 Comment(0)
V
2

In my case I was trying to present a UIAlertController at some point in the app's lifetime after using a UISearchController in the same UINavigationController.

I wasn't using the UISearchController correctly and forgot to set searchController.isActive = false before dismissing. Later on in the app I tried to present the alert but the search controller, though not visible at the time, was still controlling the presentation context.

Vixen answered 29/1, 2018 at 21:51 Comment(3)
So relieved to come across your answer; was wracking my brain trying to figure it out and mine turned out to be the UISearchController too.Commend
@JamesToomey glad I could help! I spent an inordinate amount of time wracking my own before realizing what was happening...Vixen
If you are struggling with a uisearchcontroller THIS is the answer!Gur
B
2

My problem was that (in my coordinator) i had presented a VC on a VC and then when i wanted to present the next VC(third one), presented the third VC from the first one which obviously makes the problem which is already presenting. make sure you are presenting the third one from the second VC.

secondVC.present(thirdVC, animated: true, completion: nil)
Bargeboard answered 23/5, 2020 at 14:12 Comment(0)
S
0

This is what finally worked for me, as my project didn't exactly have a NavigationVC but instead, individual detached VC's. as xib files

This code produced the bug:

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

This code fixed the bug:

 if presentedViewController == nil{
        navigationController?.present(alertVC, animated: true, completion: nil)
    }
Scimitar answered 19/2, 2018 at 23:6 Comment(0)
J
0

For me it was an alert that was interfering with the new VC that I was about to present.

So I moved the new VC present code into the OK part of my alert, Like this :

    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)
}
Joanejoanie answered 4/2, 2019 at 21:11 Comment(0)
E
0

My issue was that I was trying to present an alert from a view that wasn't on top. Make sure you present from the top-most viewController.

Estivation answered 7/10, 2019 at 23:1 Comment(0)
A
0

In my case this was an issue of a button which was duplicated in Interface Builder. The original button had a touch-up handler attached, which also presented a modal view. When I then attached a touch-up handler on the copied button, I forgot to remove the copied handler from the original, causing both handlers to be fired and thus creating the warning.

Atlantes answered 15/10, 2019 at 8:59 Comment(0)
W
0

More than likely you have your Search button wired directly to the other view controller with a segue and you are calling performSegueWithIdentifier. So you are opening it twice, which generates the error that tells you "is already presenting."

So don't call performSegueWithIdentifier, and that should do the trick.

Wineskin answered 13/8, 2020 at 22:38 Comment(0)
P
0

Make sure you Dismiss previous one before presenting new one!

Proconsulate answered 21/2, 2021 at 8:18 Comment(0)
C
0

This one fixed the error, but I still have to double-click the button to call VC. Button unavailable for a few ms. ((

let secondTVC = SecondTVC()
@objc func secondBtnAction() {
    DispatchQueue.main.async { [weak self] in
        guard let self = self else { return }
        if self.presentedViewController == nil {
            let modalNav = UINavigationController(rootViewController: self.secondTVC)
            self.navigationController?.show(modalNav, sender: AnyObject.self)
        }
    }
}
Clunk answered 5/3, 2023 at 9:35 Comment(0)
R
0

Lets say you wanna present AViewController

  1. Simply use self.present(AViewController_object)
  2. Use self.presentedViewController.present(AnotherController_object)

This way you actually present in a stack of one another

self.presentedViewController is the current controller who presented new controller

Reliquiae answered 28/3, 2024 at 16:3 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.