how to programmatically fake a touch event to a UIButton?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
In normal iOS application code, you usually should not try to fabricate a real UITouch object and inject it into the event system. UIKit is not designed for arbitrary in-process touch synthesis through public API. If your real goal is to make a UIButton behave as if it was tapped, the practical public solution is to trigger the button's control action with sendActions(for:).
Use the Control Event System, Not Fake Touch Objects
UIButton is a UIControl. When a user taps it, UIKit eventually delivers control events such as .touchUpInside. If your code wants to trigger the same application logic, call the control event directly.
In a real view controller, the pattern looks like this:
That does not create a physical touch event, but it does invoke the same target-action path your app normally uses.
Why Real Touch Synthesis Is Usually the Wrong Goal
Developers sometimes ask for a fake touch when they actually need one of these:
- trigger business logic bound to a button
- test that tapping the button causes the right behavior
- activate accessibility or UI flows in automation
Those are different problems.
Inside an app process, public UIKit APIs do not provide a supported way to construct arbitrary UITouch and UIEvent instances and inject them as if they came from the system. Trying to simulate low-level touches generally leads to brittle or private-API-dependent code, which is not appropriate for App Store apps.
For UI Testing, Use XCUITest
If your real requirement is end-to-end UI automation, use XCUITest rather than sendActions(for:).
This is the right layer for testing actual interaction. It exercises the UI more realistically than calling the action directly inside app code.
When sendActions(for:) Is Not Enough
sendActions(for:) triggers target-action methods. It does not reproduce every side effect of an actual human interaction. For example, it is not a replacement for:
- gesture recognizer pipelines
- touch tracking across multiple phases
- system-level integration tests
- animation timing driven by real gesture movement
If the code depends on touch movement, gesture recognizers, or responder-chain behavior beyond control events, you may need to refactor the application logic so it is testable separately from the raw interaction mechanism.
A Better Design for Business Logic
If tapping a button should do important work, keep that work in a method or service that both the button action and other code paths can call.
Then your code can call performSubmit() directly when UI simulation is not actually needed. This is cleaner than forcing everything through a fake event.
Common Pitfalls
A common mistake is asking for a fake touch when the real need is just to invoke the button's action. sendActions(for: .touchUpInside) is usually enough for that.
Another mistake is depending on private or unsupported APIs to build UITouch objects. That is brittle and not appropriate for production iOS code.
People also sometimes use sendActions(for:) in place of real UI testing and then assume interaction coverage is complete. It is not; it only covers the control-action path.
Finally, if the button action contains too much logic, the real problem may be design. Move the business work into a normal method that can be called and tested directly.
Summary
- In normal app code, do not try to fabricate real low-level touch events for
UIButton - To trigger button behavior programmatically, use
sendActions(for: .touchUpInside) - For end-to-end UI interaction tests, use XCUITest and call
.tap()there - '
sendActions(for:)triggers target-action logic, not a full physical touch lifecycle' - If you only need the business behavior, call a shared method directly instead of simulating UI
- Prefer supported UIKit and testing APIs over touch-injection tricks

