From d7ee960d50f575bc8a488982a3449910b0cef855 Mon Sep 17 00:00:00 2001 From: Ioannis J Date: Tue, 19 Nov 2024 14:05:22 +0200 Subject: [PATCH] fix: handle zero touch coordinates (#256) * fix: handle zero touch coordinates * chore: update CHANGELOG.md --- CHANGELOG.md | 1 + PostHog/Replay/UIApplicationTracker.swift | 20 ++++++++++++++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e9520f5c7..e806ea34b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ ## Next - fix: reading screen size could sometimes lead to a deadlock ([#252](https://github.com/PostHog/posthog-ios/pull/252)) +- fix: avoid zero touch locations ([#256](https://github.com/PostHog/posthog-ios/pull/256)) ## 3.15.3 - 2024-11-18 diff --git a/PostHog/Replay/UIApplicationTracker.swift b/PostHog/Replay/UIApplicationTracker.swift index 1ec20a41c..1fe95b413 100644 --- a/PostHog/Replay/UIApplicationTracker.swift +++ b/PostHog/Replay/UIApplicationTracker.swift @@ -51,9 +51,16 @@ return } - PostHogReplayIntegration.dispatchQueue.async { + // capture necessary touch information on the main thread before performing any asynchronous operations + // - this ensures that UITouch associated objects like UIView, UIWindow, or [UIGestureRecognizer] are still valid. + // - these objects may be released or erased by the system if accessed asynchronously, resulting in invalid/zeroed-out touch coordinates + let touchInfo = touches.map { + (phase: $0.phase, location: $0.location(in: window)) + } + + PostHogReplayIntegration.dispatchQueue.async { [touchInfo] in var snapshotsData: [Any] = [] - for touch in touches { + for touch in touchInfo { let phase = touch.phase let type: Int @@ -65,8 +72,13 @@ continue } - let posX = Int(touch.location(in: window).x) - let posY = Int(touch.location(in: window).y) + // we keep a failsafe here just in case, but this will likely never be triggered + guard touch.location != .zero else { + continue + } + + let posX = Int(touch.location.x) + let posY = Int(touch.location.y) // if the id is 0, BE transformer will set it to the virtual bodyId let touchData: [String: Any] = ["id": 0, "pointerType": 2, "source": 2, "type": type, "x": posX, "y": posY]