Once overrode touchesEnded never end even in another class or view

Hey,


I'm building an app where I've to recognize my own gesture (these by apple were too precise for my use).

To do that I'm overriding touchesBegan, touchesMoved and touchesEnded, and it appears that once it's done it's always on.


Let me try to explain it more clearly :

first view (nothing special here), everything is ok.

I perform a segue to my second view controller, that's where I'm overriding and recognizing gestures I need. Everything is almost okay but just because of my code.

I perform another segue to the first view controller, and here, all the gestures I'm recognizing in the second view controller are still recognized.


As these gesture are made to control things in the house you can easily understand the problem here.


Do you know why it does that and how to get rid of that problem?

If you want some code, just let me know please.


Thanks.

Hawkydoky

I suppose you add your gesture with addGestureRecognizer to the view in viewDidLoad (or viewWillAppear) of the second controller ?


Do you removeGestureRecognizer when you leave the view, before returning and leaving the view ?

Do you unwind segue or do you have a new segue to return to first controller ?

I think you should not have the problem with unwindSegue, because the second controller is then deleted as well as the gesture ; otherwise, the new view (1) is stacked over the previous (2) and probably messages are passed to down the chain.

Thanks for your reply.


I'm not using Apple's gesture recognizer, I can't use them for what I need. That's why I'm overriding touchesBegan and the other, I'm doing it by myself from coordinates of gestures.


Here is a sample of what I do, maybe you'll understand better what I mean.


import UIKit

    class SecondViewController: UIViewController {
    //Variables definition

    override func viewDidLoad() {
        super.viewDidLoad()
        ascending = false
        UIScreen.main.wantsSoftwareDimming = true
        UIScreen.main.brightness = (0.0)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.timer.invalidate()
        isPinched = false
        super.touchesBegan(touches, with: event)
        startTime = getCurrentMillis()
     
        for touch in touches{
            let point = touch.location(in: self.view)
            for (index,finger)  in fingers.enumerated() {
                if finger == nil {
                    fingers[index] = String(format: "%p", touch)
                 
                    if (finger1.isEmpty){
                        finger1 = [point.x, point.y]
                    }
                    //And so on until finger10
                    break
                }
            }
        }
     
        //If the gesture is long enough, I have a special recognition (longPress)

        timer = Timer.scheduledTimer(timeInterval: 0.4, target: self, selector: #selector(increaseValue), userInfo: nil, repeats: true)
        if ascending {
            ascending = false
        }
        else {
            ascending = true
        }
    }


    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesMoved(touches, with: event)
     
        for touch in touches {
            let point = touch.location(in: self.view)
            for (index,finger) in fingers.enumerated() {
                if let finger = finger, finger == String(format: "%p", touch) {
                    switch (index){
                    case 0 :
                        finger1 += [point.x, point.y]
                    //And so on until case 9 / finger10
                    default :
                        break
                    }
                }
            }
        }
    }


    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesEnded(touches, with: event)
        endTime = getCurrentMillis()
     
        for touch in touches {
            for (index,finger) in fingers.enumerated() {
                if let finger = finger, finger == String(format: "%p", touch) {
                    fingers[index] = nil
                    break
                }
            }
        }
     
        direction[0] = ""
        direction[1] = ""
        direction[2] = ""
        direction[3] = ""
        direction[4] = ""
     
        if finger1.count != 0 {
            direction[0] = GestureRecognizer(coordinates: finger1, index: 0)
        }
        if finger2.count != 0 {
            direction[1] = GestureRecognizer(coordinates: finger2, index: 1)
        }
        if finger3.count != 0 {
            direction[2] = GestureRecognizer(coordinates: finger3, index: 2)
        }
        if finger4.count != 0 {
            direction[3] = GestureRecognizer(coordinates: finger4, index: 3)
        }
        if finger5.count != 0 {
            direction[4] = GestureRecognizer(coordinates: finger5, index: 4)
        }
     
     
        if Int64(endTime - startTime) < 600 {

       //////////// HERE IS THE GESTURE RECOGNITION\\\\\\\\\\\\


            if !finger1.isEmpty && !finger2.isEmpty && !finger3.isEmpty && !finger4.isEmpty && ((((finger1[0] <= finger3[0] + 60) && (finger1[0] >= finger3[0] - 60 )) && ((finger1[1] <= finger3[1] + 60) && (finger1[1] >= finger3[1] - 60 ))) && (((finger2[0] <= finger4[0] + 60) && (finger2[0] >= finger4[0] - 60 )) && ((finger2[1] <= finger4[1] + 60) && (finger2[1] >= finger4[1] - 60 )))) {
                labelUpdate = "double tap 2 fingers"
                doubleTap2()
            }
            else if !finger1.isEmpty && !finger2.isEmpty && !finger3.isEmpty && !finger4.isEmpty && ((((finger1[0] <= finger4[0] + 60) && (finger1[0] >= finger4[0] - 60 )) && ((finger1[1] <= finger4[1] + 60) && (finger1[1] >= finger4[1] - 60 ))) && (((finger2[0] <= finger3[0] + 60) && (finger2[0] >= finger3[0] - 60 )) && ((finger2[1] <= finger3[1] + 60) && (finger2[1] >= finger3[1] - 60 )))) {
                labelUpdate = "double tap 2 fingers"
                doubleTap2()
            }
           // and so on
        }
     
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
            self.directionLabel.text = self.labelUpdate
            self.finger1 = []
            self.finger2 = []
            self.finger3 = []
            self.finger4 = []
            self.finger5 = []
            self.finger6 = []
            self.finger7 = []
            self.finger8 = []
            self.finger9 = []
            self.finger10 = []
        }
    }

    //One of the function I call
    func swipeLeftTwo(){
        request(urlAdress: "Url Adress")
    }

    func swipeRightFour(){
            self.performSegue(withIdentifier: "SecondViewController", sender:self)
    }
}


Is it better ?

OK.


I believe (it's been some time I did not look at this) that the touches are passed with events in the responder chain.


Did you try the unwindSegue ?


Or you could also intercept the touches in the first controller (overriding touches)

I did that already :

import UIKit
class ViewController: UIViewController {
   
    @IBOutlet weak var StatusLab: UILabel!
    override func viewDidLoad() {
        super.viewDidLoad()
        StatusLab.text = "Test"
        /
    }
   
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        /
    }
   
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesBegan(touches , with:event)
    }
   
    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesMoved(touches , with:event)
    }
    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
        super.touchesEnded(touches , with:event)
    }
}


But I don't know what else I can do... How do I handle that ?


I did not try the unwindSegue, i will.

Ok, I just watch what unwindSegue was, and that's not a solution for me as, for now I've only 2 view controller, but later I'll have up to 7 differents views and I'd like to pass throught them indifferently...

The problem is that you will end stacking a lot of controllers.


Could have a look here, to unload the controller after segue.


h ttps://stackoverflow.com/questions/12867711/remove-last-uiviewcontroller-after-modal-segue

Ok, I can't test much more for today, but I think I've something with:


self.dismiss(animated: true, completion: nil)


Thank you much for your time and advices!
Hope I've found the right thing 🙂

Let us know when that works.


I remember viewing a tutorial explaining in detail this stacking or dismissing of view controllers after segue (Stanford course ?).

Hi,


So I had more time today to try.

When using :

self.dismiss(animated: true, completion: nil)
self.performSegue(withIdentifier: "SecondViewController", sender:self)


I have no problem of gesture recognition anymore, but, it doesn't show the viewController I want, it goes back to the previous one is that a normal behavior ?


Plus I've this warning in the console :


Warning: Attempt to present <APP.ViewController: 0x100c36bc0> on <APP.SecondViewController: 0x100c33320> whose view is not in the window hierarchy!


Don't really understand why, as, with a few researches, I've seen the same problem but people were trying to do so in the viewDidLoad() function, that's not my case.


I've searched a bit and found something with :



weak var pvc = self.presentingViewController
self.dismiss(animated: true) {
     pvc?.performSegue(withIdentifier: "SecondViewController", sender: nil)
}


But that's not working 😟

I would try to put the performSegue in the completion handler.


Something like :


self.dismiss(animated: true, completion: { self.performSegue(withIdentifier: "SecondViewController", sender:self) } )


Otherwise, the dismiss deletes the controller : this returns you to the previous one, and performSegue is not executed.


Edited: I see that's very similar to what you have just tried.

Yes, that does exactly the same thing as what I alredy tried, it's going back to the previous viewController and not the one I'm aiming.

Just to check:

- which controller would you like to go to after dismissing ?

- Is it the one pointed to by Identifier: "SecondViewController"

Once overrode touchesEnded never end even in another class or view
 
 
Q