iOS
UIView
Touch Events
Controller
Swift

UIView touch event in controller

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Touch handling in iOS can happen in a view subclass, in a view controller, or through a gesture recognizer. The right choice depends on what you are trying to detect. If you just need tap-like interaction in a controller, a gesture recognizer is usually cleaner than overriding raw touch methods.

Raw touchesBegan, touchesMoved, and related methods still matter when you need fine-grained touch tracking. The important detail is understanding where those events actually arrive in the responder chain.

Where Touch Events Should Live

UIView inherits from UIResponder, so a view can receive low-level touch callbacks directly. A UIViewController also participates in the responder system, but the controller is not usually the first place touch events land. The touched view receives them first.

That means:

  • use a custom UIView subclass when the view itself owns the interaction,
  • use a gesture recognizer when the controller only needs high-level gestures,
  • override controller touch methods only when you specifically want controller-level raw touch handling.

For most apps, gesture recognizers are the best default.

Preferred Approach: Gesture Recognizer in the Controller

If your controller wants to react when the user taps a view, add a UITapGestureRecognizer:

swift
1import UIKit
2
3final class DemoViewController: UIViewController {
4    private let boxView: UIView = {
5        let view = UIView()
6        view.translatesAutoresizingMaskIntoConstraints = false
7        view.backgroundColor = .systemBlue
8        return view
9    }()
10
11    override func viewDidLoad() {
12        super.viewDidLoad()
13        view.backgroundColor = .white
14        view.addSubview(boxView)
15
16        NSLayoutConstraint.activate([
17            boxView.widthAnchor.constraint(equalToConstant: 160),
18            boxView.heightAnchor.constraint(equalToConstant: 160),
19            boxView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
20            boxView.centerYAnchor.constraint(equalTo: view.centerYAnchor)
21        ])
22
23        let tap = UITapGestureRecognizer(target: self, action: #selector(handleTap))
24        boxView.addGestureRecognizer(tap)
25    }
26
27    @objc private func handleTap() {
28        print("Box tapped")
29    }
30}

This keeps the touch interpretation in UIKit's gesture system instead of forcing you to manually inspect UITouch objects.

When a Custom View Is Better

If the interaction belongs to the view itself, such as drawing, dragging, or custom hit-testing, override touch methods in a UIView subclass:

swift
1import UIKit
2
3final class DrawingView: UIView {
4    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
5        guard let touch = touches.first else { return }
6        print("Touch began at", touch.location(in: self))
7    }
8
9    override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
10        guard let touch = touches.first else { return }
11        print("Touch moved to", touch.location(in: self))
12    }
13
14    override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
15        print("Touch ended")
16    }
17}

This is the right place for raw touch state because the view is the thing being interacted with.

Controller-Level Raw Touches

You can override touch methods in a UIViewController, but it is usually a specialized choice:

swift
1override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
2    super.touchesBegan(touches, with: event)
3    print("Controller noticed a touch")
4}

This works only when the responder chain reaches the controller. If a child view handles the touch or a gesture recognizer consumes it, the controller may not see what you expect. That is why controller-level raw touch handling is often surprising.

Common Pitfalls

  • Overriding raw touch methods in the controller when a gesture recognizer would be simpler and more reliable.
  • Expecting the controller to receive every touch before the view does. The touched view usually gets first chance.
  • Forgetting isUserInteractionEnabled on custom views that should respond to gestures.
  • Putting heavy work inside touch callbacks, which can make scrolling and animations feel laggy.
  • Handling only touchesBegan and ignoring moved, ended, or cancelled states when the interaction needs full tracking.

Summary

  • Gesture recognizers are usually the cleanest way to handle taps and common gestures in a controller.
  • Custom UIView subclasses are the right place for raw touch tracking owned by the view itself.
  • Controller-level touch overrides are possible, but they are not the best default.
  • The responder chain determines where touch events actually arrive.
  • Choose the highest-level API that matches the interaction you need.

Course illustration
Course illustration

All Rights Reserved.