From d5f98608981631e224f483dbcea30939ad44db27 Mon Sep 17 00:00:00 2001 From: Stefan Ceriu Date: Mon, 31 Mar 2025 08:49:57 +0300 Subject: [PATCH] Bring back the background refresh stop sync crash fix, this time with a forced conformance to the main actor. - follow up to https://github.com/element-hq/element-x-ios/pull/3942 and https://github.com/element-hq/element-x-ios/pull/3946 --- .../Sources/Application/AppCoordinator.swift | 23 ++++++++++++++----- 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/ElementX/Sources/Application/AppCoordinator.swift b/ElementX/Sources/Application/AppCoordinator.swift index a59c53706..8af56d267 100644 --- a/ElementX/Sources/Application/AppCoordinator.swift +++ b/ElementX/Sources/Application/AppCoordinator.swift @@ -895,8 +895,11 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg // Attempt to stop the background task sync loop cleanly, only if the app not already running return } - userSession?.clientProxy.stopSync(completion: completion) - clientProxyObserver = nil + + MainActor.assumeIsolated { + userSession?.clientProxy.stopSync(completion: completion) + clientProxyObserver = nil + } } private func startSync() { @@ -1038,12 +1041,20 @@ class AppCoordinator: AppCoordinatorProtocol, AuthenticationFlowCoordinatorDeleg // This is important for the app to keep refreshing in the background scheduleBackgroundAppRefresh() - task.expirationHandler = { [weak self] in + /// We have a lot of crashes stemming here which we previously believed are caused by stopSync not being async + /// on the client proxy side (see the comment on that method). We have now realised that will likely not fix anything but + /// we also noticed this does not crash on the main thread, even though the whole AppCoordinator is on the Main actor. + /// As such, we introduced a MainActor conformance on the expirationHandler but we are also assuming main actor + /// isolated in the `stopSync` method above. + /// https://sentry.tools.element.io/organizations/element/issues/4477794/ + task.expirationHandler = { @Sendable [weak self] in MXLog.info("Background app refresh task is about to expire.") - self?.stopSync(isBackgroundTask: true) { - MXLog.info("Marking Background app refresh task as complete.") - task.setTaskCompleted(success: true) + Task { @MainActor in + self?.stopSync(isBackgroundTask: true) { + MXLog.info("Marking Background app refresh task as complete.") + task.setTaskCompleted(success: true) + } } }