21

I have a long press gesture set on a UITableView that presents a UIAlertController containing the cell's text. When the UIAlertController is presented I get this warning:

Attempt to present <UIAlertController: 0x7fd57384e8e0>  on <TaskAppV2.MainTaskView: 0x7fd571701150> which is already presenting (null)

From my understanding, MainTaskView (the UITableView) is already presenting a view, so it shouldn't present a second view, the UIAlertController. So I tried this solution from a similar question. It does not work as I get the same warning. What can I do to solve this warning? See below for code:

func longPressedView(gestureRecognizer: UIGestureRecognizer){

    /*Get cell info from where user tapped*/
    if (gestureRecognizer.state == UIGestureRecognizerState.Ended) {
        var tapLocation: CGPoint = gestureRecognizer.locationInView(self.tableView)

        var tappedIndexPath: NSIndexPath? = self.tableView.indexPathForRowAtPoint(tapLocation)
        if (tappedIndexPath != nil) {
            var tappedCell: UITableViewCell? = self.tableView.cellForRowAtIndexPath(tappedIndexPath!)
            println("the cell task name is \(tappedCell!.textLabel!.text!)")
        } else {
            println("You didn't tap on a cell")
        }
    }

    /*Long press alert*/
    let tapAlert = UIAlertController(title: "Long Pressed", message: "You just long pressed the long press view", preferredStyle: UIAlertControllerStyle.Alert)
    tapAlert.addAction(UIAlertAction(title: "OK", style: .Destructive, handler: nil))
    /*
    if (self.presentedViewController == nil) {
        self.presentViewController(tapAlert, animated: true, completion: nil)
    } else {
        println("already presenting a view")
    } */

    self.presentViewController(tapAlert, animated: true, completion: nil)
    println("presented")
}

Console output:

presented
You didn't tap on a cell
2015-05-19 22:46:35.692 TaskAppV2[60765:3235207] Warning: Attempt to present <UIAlertController: 0x7fc689e05d80>  on <TaskAppV2.MainTaskView: 0x7fc689fc33f0> which is already presenting (null)
presented

For some reason, both pieces of code are executing in the if statement when the long press gesture happens. The alert is presented and the text is printed to the console. Is this an issue?

Edit: As Matt said, I didn't have all my code in the scope of the gesture recognizer test. Moving that in fixed my problem. The code outside of the test was being executed twice, resulting in the UIAlertController being presented twice.

Community
  • 1
  • 1
MortalMan
  • 2,582
  • 3
  • 23
  • 47
  • Can we see the relevant code? View *controllers* present other *controllers*, so your UITableView shouldn't be the issue. It seems you're mixing up views and controllers a bit. – Connor Neville May 20 '15 at 01:22
  • The accepted answer on the question you linked to seems pretty clear. Can you add some relevant code to your question? – Daniel Storm May 20 '15 at 01:23
  • Sure, give me a couple minutes. – MortalMan May 20 '15 at 01:23
  • "This line of code silences the warning" Because it is totally different. Instead of dismissing the existing presented v.c. and presenting a new one, you now have _two_ presented view controllers one on top of the other. If that's what you want, fine. But make sure that it is. – matt May 20 '15 at 02:10
  • @matt is there a proper way to do this then? – MortalMan May 20 '15 at 02:14
  • What view controller is already being presented? The message `which is already presenting (null)` seems very odd. That is the thing to try to track down first. – matt May 20 '15 at 02:16
  • Hang on, I have a Cunning Plan... – matt May 20 '15 at 02:18
  • @matt `println("\(presentedViewController)")` yields nil. Which I guess makes sense. What can I do to track this down? – MortalMan May 20 '15 at 02:19
  • 1
    I have a theory that this is because long-pressing a table cell summons the menu. You are in conflict with that. My answer below _might_ get us out of this. – matt May 20 '15 at 02:21
  • @matt that didn't work :( anything else we can try? – MortalMan May 20 '15 at 02:27
  • Are we in a popover? Describe the whole situation as best you can, please. – matt May 20 '15 at 02:28
  • Brilliant theory, matt! (I upvoted that, because most of us wouldn't have thought of that!) But the labels would have to have userInteractionEnabled, right? (I don't get a menu on my custom cells.) –  May 20 '15 at 02:29
  • Okay, I have a new theory! Hang on, this one will really get you. – matt May 20 '15 at 02:34
  • A table view takes up the majority of the window. A `gestureRecognizer` is set up in MainTaskView's (table controller) `viewDidLoad`. When a cell or empty table view is long pressed, the function I made for the gesture is called. I will update the question. – MortalMan May 20 '15 at 02:35

3 Answers3

18

For some reason, both pieces of code are executing in the if

That should have rung alarm bells for me. It is impossible that both the if and the else should run. This code must be running twice.

That is because you are not testing the state of the gesture recognizer. A long press g.r. sends its action message twice. You are running this code both on the long press and on the release. You need to test the state of the g.r. so that you don't do that. Example:

@IBAction func longPressedView(g: UIGestureRecognizer) {
    if g.state == .Began {
        // ... do it all here
    }
}
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • The only other `presentViewController` I have in this class is only possible while the table is in edit mode. – MortalMan May 20 '15 at 02:38
  • 2
    Genius! I put a `println()` under the `presentViewController` and it gets executed twice per long press. – MortalMan May 20 '15 at 02:41
  • I've got it. It's because you're not testing the state of the long press. Revised my answer (for the last time, I think). – matt May 20 '15 at 02:42
  • But there's your problem. Your alert stuff is not _in_ the test! Move it in. Otherwise it happens twice. – matt May 20 '15 at 02:46
  • Oh my god I am so sorry for wasting your time... I bought your two books on iOS 8 programming a couple days ago and have had fun reading them. I am hoping they help me learn all this stuff. – MortalMan May 20 '15 at 02:49
  • Not a waste, absolutely fascinating. I had completely forgotten about the issue with multiple calls to the action method, I should have thought of this sooner. – matt May 20 '15 at 02:51
16

I have had the same issue. I was able to fix it by this code:

        if self.presentedViewController == nil {
            self.present(Alert, animated: true, completion: nil)
        }
        else {
            self.dismiss(animated: false, completion: nil)
            self.present(Alert, animated: true, completion: nil)
        }
0

You should differentiate the gesture state then execute the code you want, if not the selector you add to target will be executed first time when the gesture's state is UIGestureRecognizerStateBegan and second time when the gesture's state is UIGestureRecognizerStateCancelled, the second performance, alertController is showing, so Xcode will log warning.

Immanito
  • 49
  • 5