Search code examples
swiftuipangesturerecognizer

why is my gestureRecognizer returning nil?


I have tried to combine numerous tutorials to try and make a gesture recognizer start an animation on a tableView once a gesture is received on a mapView (shrinking table once map is moved like the old uber app). The animation functions, however once the animation is finished i am receiving "unexpectedly found nil when unwrapping an optional" - however it seems like it should not be nil, obviously it is, i just dont understand how. The error is 3/4 the way down, ive tried to reduce as much code as possible so parts are missing. My guess is that i have created 2 gesture recognizers which is causing the issue, but i am unsure how to combine them. Here is the code:

    class RestaurantsVC: UIViewController, MKMapViewDelegate, CLLocationManagerDelegate, UIGestureRecognizerDelegate {

    var animator: UIViewPropertyAnimator?
    var currentState: AnimationState!
    var thumbnailFrame: CGRect!
    var panGestureRecognizer: UIPanGestureRecognizer!

    override func viewDidLoad() {
        super.viewDidLoad()

        let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(RestaurantsVC.handlePan(gestureRecognizer:)))
        panGestureRecognizer.delegate = self
        self.mapView.addGestureRecognizer(panGestureRecognizer)
}

    func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }


    @objc func handlePan (gestureRecognizer: UIPanGestureRecognizer) {
        let translation = gestureRecognizer.translation(in: self.view.superview)

        switch gestureRecognizer.state {
        case .began:
            startPanning()
            animator?.startAnimation()
        case .ended:
            let velocity = gestureRecognizer.velocity(in: self.view.superview)
            endAnimation(translation: translation, velocity: velocity)
        default:
            print("Something went wrong handlePan")
        }
    }


    func startPanning() {
        var finalFrame:CGRect = CGRect()
        switch currentState {
           // code
        }
        animator = UIViewPropertyAnimator(duration: 1, dampingRatio: 0.8, animations: {
        })
    }


    func endAnimation (translation:CGPoint, velocity:CGPoint) {

            if let animator = self.animator {
                self.panGestureRecognizer.isEnabled = false //(this line is where i get the error)//

                switch self.currentState {
                case .thumbnail:
                        animator.isReversed = false
                        animator.addCompletion({ _ in
                            self.currentState = .minimized
                            self.panGestureRecognizer.isEnabled = true
                        })
                case .minimized:
                        animator.isReversed = true
                        animator.addCompletion({ _ in
                            self.currentState = .thumbnail
                            self.panGestureRecognizer.isEnabled = true
                        })
                default:
                    print("unknown state")
                }
            }
    }
}

Solution

  • It's nil because you're never actually assigning it.

    In your viewDidLoad() function, you're actually redefining a local variable which shadows the instance variable:

    let panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(RestaurantsVC.handlePan(gestureRecognizer:)))
    ^ The 'let' keyword is redefining this variable at the local scope
    

    You should remove the let declaration, and instead assign this as:

    self.panGestureRecognizer = UIPanGestureRecognizer(target: self, action: #selector(RestaurantsVC.handlePan(gestureRecognizer:)))