diff --git a/ElementX.xcodeproj/project.pbxproj b/ElementX.xcodeproj/project.pbxproj index d8496bf96c..a95290ac77 100644 --- a/ElementX.xcodeproj/project.pbxproj +++ b/ElementX.xcodeproj/project.pbxproj @@ -3,7 +3,7 @@ archiveVersion = 1; classes = { }; - objectVersion = 51; + objectVersion = 52; objects = { /* Begin PBXBuildFile section */ @@ -137,6 +137,7 @@ 54C774874BED4A8FAD1F22FE /* AnalyticsConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = D77B3D4950F1707E66E4A45A /* AnalyticsConfiguration.swift */; }; 563A05B43207D00A6B698211 /* OIDCService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9010EE0CC913D095887EF36E /* OIDCService.swift */; }; 56F0A22972A3BB519DA2261C /* HomeScreenViewModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 24F5530B2212862FA4BEFF2D /* HomeScreenViewModelProtocol.swift */; }; + 5706B6600CCCFE254F7D2495 /* Task.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA2CA6D7090404B1074E887F /* Task.swift */; }; 59C41313AED7566C3AC51163 /* RoomSummary.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29A953B6C0C431DBF4DD00B4 /* RoomSummary.swift */; }; 5B2C4C17888FC095ED6880B2 /* SplashViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 48971F1FFD7FC5C466889FC7 /* SplashViewController.xib */; }; 5C8AFBF168A41E20835F3B86 /* LoginScreenUITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1DB34B0C74CD242FED9DD069 /* LoginScreenUITests.swift */; }; @@ -321,7 +322,6 @@ E01373F2043E76393A0CE073 /* AnalyticsPromptViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A11B74ACE8D71747E1044A9C /* AnalyticsPromptViewModel.swift */; }; E0A4DCA633D174EB43AD599F /* BackgroundTaskProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2CA028DCD4157F9A1F999827 /* BackgroundTaskProtocol.swift */; }; E1DF24D085572A55C9758A2D /* Bundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6E89E530A8E92EC44301CA1 /* Bundle.swift */; }; - E290C78E7F09F47FD2662986 /* Task.swift in Sources */ = {isa = PBXBuildFile; fileRef = A40C19719687984FD9478FBE /* Task.swift */; }; E3CA565A4B9704F191B191F0 /* JoinedRoomSize+MemberCount.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBF9AEA706926DD0DA2B954C /* JoinedRoomSize+MemberCount.swift */; }; E47CD939D8480657D4B706C6 /* AnalyticsPromptCheckmarkItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = BA7B2E9CC5DC3B76ADC35A43 /* AnalyticsPromptCheckmarkItem.swift */; }; E481C8FDCB6C089963C95344 /* DTCoreText in Frameworks */ = {isa = PBXBuildFile; productRef = 527578916BD388A09F5A8036 /* DTCoreText */; }; @@ -628,7 +628,7 @@ 8D6094DEAAEB388E1AE118C6 /* MockRoomTimelineProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockRoomTimelineProvider.swift; sourceTree = ""; }; 8D8169443E5AC5FF71BFB3DB /* cs */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = cs; path = cs.lproj/Localizable.strings; sourceTree = ""; }; 8DC2C9E0E15C79BBDA80F0A2 /* TimelineStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineStyle.swift; sourceTree = ""; }; - 8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; path = UITests.xctestplan; sourceTree = ""; }; + 8E088F2A1B9EC529D3221931 /* UITests.xctestplan */ = {isa = PBXFileReference; lastKnownFileType = text; path = UITests.xctestplan; sourceTree = ""; }; 8F7D42E66E939B709C1EC390 /* MockRoomSummaryProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockRoomSummaryProvider.swift; sourceTree = ""; }; 9010EE0CC913D095887EF36E /* OIDCService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OIDCService.swift; sourceTree = ""; }; 90733775209F4D4D366A268F /* RootRouterType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RootRouterType.swift; sourceTree = ""; }; @@ -667,7 +667,6 @@ A1ED7E89865201EE7D53E6DA /* SeparatorRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SeparatorRoomTimelineItem.swift; sourceTree = ""; }; A2B6433F516F1E6DFA0E2D89 /* vls */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = vls; path = vls.lproj/Localizable.strings; sourceTree = ""; }; A30A1758E2B73EF38E7C42F8 /* ServerSelectionModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerSelectionModels.swift; sourceTree = ""; }; - A40C19719687984FD9478FBE /* Task.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Task.swift; sourceTree = ""; }; A436057DBEA1A23CA8CB1FD7 /* UIFont+AttributedStringBuilder.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIFont+AttributedStringBuilder.h"; sourceTree = ""; }; A443FAE2EE820A5790C35C8D /* et */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = et; path = et.lproj/Localizable.strings; sourceTree = ""; }; A4756C5A8C8649AD6C10C615 /* MockUserSession.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockUserSession.swift; sourceTree = ""; }; @@ -821,6 +820,7 @@ F77C060C2ACC4CB7336A29E7 /* EmoteRoomTimelineItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineItem.swift; sourceTree = ""; }; F9E785D5137510481733A3E8 /* TextRoomTimelineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextRoomTimelineView.swift; sourceTree = ""; }; FA154570F693D93513E584C1 /* RoomMessageFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomMessageFactory.swift; sourceTree = ""; }; + FA2CA6D7090404B1074E887F /* Task.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Task.swift; sourceTree = ""; }; FAB10E673916D2B8D21FD197 /* TemplateModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TemplateModels.swift; sourceTree = ""; }; FDB9C37196A4C79F24CE80C6 /* KeychainControllerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeychainControllerTests.swift; sourceTree = ""; }; /* End PBXFileReference section */ @@ -1092,9 +1092,9 @@ children = ( B6E89E530A8E92EC44301CA1 /* Bundle.swift */, A9FAFE1C2149E6AC8156ED2B /* Collection.swift */, + FA2CA6D7090404B1074E887F /* Task.swift */, E26747B3154A5DBC3A7E24A5 /* Image.swift */, 40B21E611DADDEF00307E7AC /* String.swift */, - A40C19719687984FD9478FBE /* Task.swift */, 287FC98AF2664EAD79C0D902 /* UIDevice.swift */, 227AC5D71A4CE43512062243 /* URL.swift */, ); @@ -2347,6 +2347,7 @@ DCB781BD227CA958809AFADF /* Coordinator.swift in Sources */, C4F69156C31A447FEFF2A47C /* DTHTMLElement+AttributedStringBuilder.swift in Sources */, EE8491AD81F47DF3C192497B /* DecorationTimelineItemProtocol.swift in Sources */, + 5706B6600CCCFE254F7D2495 /* Task.swift in Sources */, FE4593FC2A02AAF92E089565 /* ElementAnimations.swift in Sources */, 06E93B2E3B32740B40F47CC5 /* ElementNavigationController.swift in Sources */, 9738F894DB1BD383BE05767A /* ElementSettings.swift in Sources */, @@ -2490,7 +2491,6 @@ 2F94054F50E312AF30BE07F3 /* String.swift in Sources */, A7D48E44D485B143AADDB77D /* Strings+Untranslated.swift in Sources */, 066A1E9B94723EE9F3038044 /* Strings.swift in Sources */, - E290C78E7F09F47FD2662986 /* Task.swift in Sources */, 43FD77998F33C32718C51450 /* TemplateCoordinator.swift in Sources */, 63C9AF0FB8278AF1C0388A0C /* TemplateModels.swift in Sources */, 1555A7643D85187D4851040C /* TemplateScreen.swift in Sources */, diff --git a/ElementX/Sources/Other/Extensions/Task.swift b/ElementX/Sources/Other/Extensions/Task.swift index 108af136e8..678fd58372 100644 --- a/ElementX/Sources/Other/Extensions/Task.swift +++ b/ElementX/Sources/Other/Extensions/Task.swift @@ -16,33 +16,46 @@ import Foundation -extension Task where Failure == Never { - static func dispatched(on queue: DispatchQueue, - priority: TaskPriority? = nil, - operation: @escaping @Sendable () -> Success) -> Task { - Task.detached(priority: priority) { - await withCheckedContinuation { continuation in - queue.async { - continuation.resume(returning: operation()) - } +public extension Task where Success == Never, Failure == Never { + /// Dispatches the given closure onto the given queue, wrapped within + /// a continuation to make it non-blocking and awaitable. + /// + /// Use this method to `await` blocking calls to the SDK from a `Task`. + /// + /// - Parameters: + /// - queue: The queue to run the closure on. + /// - function: A string identifying the declaration that is the notional + /// source for the continuation, used to identify the continuation in + /// runtime diagnostics related to misuse of this continuation. + /// - body: A sendable closure. Use of sendable won't work as it isn't + /// async, but is added to enforce actor semantics. + static func dispatch(on queue: DispatchQueue, function: String = #function, _ body: @escaping @Sendable () -> T) async -> T { + await withCheckedContinuation(function: function) { continuation in + queue.async { + continuation.resume(returning: body()) } } } -} -extension Task where Failure == Error { - static func dispatched(on queue: DispatchQueue, - priority: TaskPriority? = nil, - operation: @escaping @Sendable () throws -> Success) -> Task { - Task.detached(priority: priority) { - try await withCheckedThrowingContinuation { continuation in - queue.async { - do { - let result = try operation() - continuation.resume(returning: result) - } catch { - continuation.resume(throwing: error) - } + /// Dispatches the given throwing closure onto the given queue, wrapped within + /// a continuation to make it non-blocking and awaitable. + /// + /// Use this method to `await` blocking calls to the SDK from a `Task`. + /// + /// - Parameters: + /// - queue: The queue to run the closure on. + /// - function: A string identifying the declaration that is the notional + /// source for the continuation, used to identify the continuation in + /// runtime diagnostics related to misuse of this continuation. + /// - body: A sendable closure. Use of sendable won't work as it isn't + /// async, but is added to enforce actor semantics. + static func dispatch(on queue: DispatchQueue, function: String = #function, _ body: @escaping @Sendable () throws -> T) async throws -> T { + try await withCheckedThrowingContinuation(function: function) { continuation in + queue.async { + do { + continuation.resume(returning: try body()) + } catch { + continuation.resume(throwing: error) } } } diff --git a/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilder.swift b/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilder.swift index 446002056e..b56c2856a9 100644 --- a/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilder.swift +++ b/ElementX/Sources/Other/HTMLParsing/AttributedStringBuilder.swift @@ -23,9 +23,9 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol { private let linkColor = UIColor.blue func fromPlain(_ string: String?) async -> AttributedString? { - await Task.detached { + await Task.dispatch(on: .global()) { fromPlain(string) - }.value + } } func fromPlain(_ string: String?) -> AttributedString? { @@ -41,9 +41,9 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol { } func fromHTML(_ htmlString: String?) async -> AttributedString? { - await Task.detached { + await Task.dispatch(on: .global()) { fromHTML(htmlString) - }.value + } } // Do not use the default HTML renderer of NSAttributedString because this method diff --git a/ElementX/Sources/Services/Authentication/AuthenticationServiceProxy.swift b/ElementX/Sources/Services/Authentication/AuthenticationServiceProxy.swift index a7c4b1d35a..aa47c6e7f7 100644 --- a/ElementX/Sources/Services/Authentication/AuthenticationServiceProxy.swift +++ b/ElementX/Sources/Services/Authentication/AuthenticationServiceProxy.swift @@ -40,29 +40,26 @@ class AuthenticationServiceProxy: AuthenticationServiceProxyProtocol { // MARK: - Public func configure(for homeserverAddress: String) async -> Result { - let task = Task.detached { () -> LoginHomeserver in + do { var homeserver = LoginHomeserver(address: homeserverAddress, loginMode: .unknown) - try self.authenticationService.configureHomeserver(serverName: homeserverAddress) - - guard let details = self.authenticationService.homeserverDetails() else { return homeserver } + try await Task.dispatch(on: .global()) { + try self.authenticationService.configureHomeserver(serverName: homeserverAddress) + } - if let issuer = details.authenticationIssuer(), let issuerURL = URL(string: issuer) { - homeserver.loginMode = .oidc(issuerURL) - } else if details.supportsPasswordLogin() { - homeserver.loginMode = .password - } else { - homeserver.loginMode = .unsupported + if let details = authenticationService.homeserverDetails() { + if let issuer = details.authenticationIssuer(), let issuerURL = URL(string: issuer) { + homeserver.loginMode = .oidc(issuerURL) + } else if details.supportsPasswordLogin() { + homeserver.loginMode = .password + } else { + homeserver.loginMode = .unsupported + } } - return homeserver - } - - switch await task.result { - case .success(let homeserver): self.homeserver = homeserver return .success(()) - case .failure(let error): + } catch { MXLog.error("Failed configuring a server: \(error)") return .failure(.invalidHomeserverAddress) } @@ -105,20 +102,19 @@ class AuthenticationServiceProxy: AuthenticationServiceProxyProtocol { } func login(username: String, password: String, initialDeviceName: String?, deviceId: String?) async -> Result { - Benchmark.startTrackingForIdentifier("Login", message: "Started new login") - - let loginTask: Task = Task.detached { - try self.authenticationService.login(username: username, - password: password, - initialDeviceName: initialDeviceName, - deviceId: deviceId) - } + do { + Benchmark.startTrackingForIdentifier("Login", message: "Started new login") - switch await loginTask.result { - case .success(let client): + let client = try await Task.dispatch(on: .global()) { + try self.authenticationService.login(username: username, + password: password, + initialDeviceName: initialDeviceName, + deviceId: deviceId) + } + Benchmark.endTrackingForIdentifier("Login", message: "Finished login") return await userSession(for: client) - case .failure(let error): + } catch { Benchmark.endTrackingForIdentifier("Login", message: "Login failed") MXLog.error("Failed logging in with error: \(error)") diff --git a/ElementX/Sources/Services/Client/ClientProxy.swift b/ElementX/Sources/Services/Client/ClientProxy.swift index c52e9b12a8..de233a8911 100644 --- a/ElementX/Sources/Services/Client/ClientProxy.swift +++ b/ElementX/Sources/Services/Client/ClientProxy.swift @@ -182,7 +182,7 @@ class ClientProxy: ClientProxyProtocol { } func loadUserDisplayName() async -> Result { - await Task.detached { + await Task.dispatch(on: .global()) { do { let displayName = try self.client.displayName() return .success(displayName) @@ -190,11 +190,10 @@ class ClientProxy: ClientProxyProtocol { return .failure(.failedRetrievingDisplayName) } } - .value } func loadUserAvatarURLString() async -> Result { - await Task.detached { + await Task.dispatch(on: .global()) { do { let avatarURL = try self.client.avatarUrl() return .success(avatarURL) @@ -202,7 +201,6 @@ class ClientProxy: ClientProxyProtocol { return .failure(.failedRetrievingAvatarURL) } } - .value } func accountDataEvent(type: String) async -> Result where Content: Decodable { @@ -218,21 +216,21 @@ class ClientProxy: ClientProxyProtocol { } func loadMediaContentForSource(_ source: MatrixRustSDK.MediaSource) async throws -> Data { - try await Task.detached { + try await Task.dispatch(on: .global()) { let bytes = try self.client.getMediaContent(source: source) return Data(bytes: bytes, count: bytes.count) - }.value + } } func loadMediaThumbnailForSource(_ source: MatrixRustSDK.MediaSource, width: UInt, height: UInt) async throws -> Data { - try await Task.detached { + try await Task.dispatch(on: .global()) { let bytes = try self.client.getMediaThumbnail(source: source, width: UInt64(width), height: UInt64(height)) return Data(bytes: bytes, count: bytes.count) - }.value + } } func sessionVerificationControllerProxy() async -> Result { - await Task.detached { + await Task.dispatch(on: .global()) { do { let sessionVerificationController = try self.client.getSessionVerificationController() return .success(SessionVerificationControllerProxy(sessionVerificationController: sessionVerificationController)) @@ -240,7 +238,6 @@ class ClientProxy: ClientProxyProtocol { return .failure(.failedRetrievingSessionVerificationController) } } - .value } func logout() async { diff --git a/ElementX/Sources/Services/Room/RoomProxy.swift b/ElementX/Sources/Services/Room/RoomProxy.swift index 42890e4ca3..a4c60352ec 100644 --- a/ElementX/Sources/Services/Room/RoomProxy.swift +++ b/ElementX/Sources/Services/Room/RoomProxy.swift @@ -105,16 +105,15 @@ class RoomProxy: RoomProxyProtocol { } func loadAvatarURLForUserId(_ userId: String) async -> Result { - await Task.detached { () -> Result in - do { - let avatarURL = try self.room.memberAvatarUrl(userId: userId) - await self.update(avatarURL: avatarURL, forUserId: userId) - return .success(avatarURL) - } catch { - return .failure(.failedRetrievingMemberAvatarURL) + do { + let avatarURL = try await Task.dispatch(on: .global()) { + try self.room.memberAvatarUrl(userId: userId) } + update(avatarURL: avatarURL, forUserId: userId) + return .success(avatarURL) + } catch { + return .failure(.failedRetrievingMemberAvatarURL) } - .value } func displayNameForUserId(_ userId: String) -> String? { @@ -122,33 +121,29 @@ class RoomProxy: RoomProxyProtocol { } func loadDisplayNameForUserId(_ userId: String) async -> Result { - await Task.detached { () -> Result in - do { - let displayName = try self.room.memberDisplayName(userId: userId) - await self.update(displayName: displayName, forUserId: userId) - return .success(displayName) - } catch { - return .failure(.failedRetrievingMemberDisplayName) + do { + let displayName = try await Task.dispatch(on: .global()) { + try self.room.memberDisplayName(userId: userId) } + update(displayName: displayName, forUserId: userId) + return .success(displayName) + } catch { + return .failure(.failedRetrievingMemberDisplayName) } - .value } - + func loadDisplayName() async -> Result { - await Task.detached { () -> Result in - if let displayName = await self.displayName { - return .success(displayName) - } - - do { - let displayName = try self.room.displayName() - await self.update(displayName: displayName) - return .success(displayName) - } catch { - return .failure(.failedRetrievingDisplayName) + if let displayName = displayName { return .success(displayName) } + + do { + let displayName = try await Task.dispatch(on: .global()) { + try self.room.displayName() } + update(displayName: displayName) + return .success(displayName) + } catch { + return .failure(.failedRetrievingDisplayName) } - .value } private func addTimelineListener(listener: TimelineListener) { @@ -160,20 +155,20 @@ class RoomProxy: RoomProxyProtocol { return .failure(.noMoreMessagesToBackPaginate) } - MXLog.debug("BackPagination") - return await Task.detached { - do { - let id = await self.id - + let id = id // Copy the ID due to @Sendable requirement. + + do { + let outcome: PaginationOutcome = try await Task.dispatch(on: .global()) { Benchmark.startTrackingForIdentifier("BackPagination \(id)", message: "Backpaginating \(count) message(s) in room \(id)") - await self.update(backPaginationOutcome: try self.room.paginateBackwards(limit: UInt16(count))) + let outcome = try self.room.paginateBackwards(limit: UInt16(count)) Benchmark.endTrackingForIdentifier("BackPagination \(id)", message: "Finished backpaginating \(count) message(s) in room \(id)") - return .success(()) - } catch { - return .failure(.failedPaginatingBackwards) + return outcome } + update(backPaginationOutcome: outcome) + return .success(()) + } catch { + return .failure(.failedPaginatingBackwards) } - .value } func sendMessage(_ message: String, inReplyToEventId: String? = nil) async -> Result { @@ -184,7 +179,7 @@ class RoomProxy: RoomProxyProtocol { let transactionId = genTransactionId() - return await Task.dispatched(on: concurrentDispatchQueue, operation: { + return await Task.dispatch(on: .global()) { do { if let inReplyToEventId = inReplyToEventId { try self.room.sendReply(msg: message, inReplyToEventId: inReplyToEventId, txnId: transactionId) @@ -196,8 +191,7 @@ class RoomProxy: RoomProxyProtocol { } catch { return .failure(.failedSendingMessage) } - }) - .value + } } func redact(_ eventID: String) async -> Result { diff --git a/ElementX/Sources/Services/SessionVerification/SessionVerificationControllerProxy.swift b/ElementX/Sources/Services/SessionVerification/SessionVerificationControllerProxy.swift index 0b739a8f30..8e74d8d5fa 100644 --- a/ElementX/Sources/Services/SessionVerification/SessionVerificationControllerProxy.swift +++ b/ElementX/Sources/Services/SessionVerification/SessionVerificationControllerProxy.swift @@ -63,7 +63,7 @@ class SessionVerificationControllerProxy: SessionVerificationControllerProxyProt } func requestVerification() async -> Result { - await Task.detached { + await Task.dispatch(on: .global()) { do { try self.sessionVerificationController.requestVerification() return .success(()) @@ -71,11 +71,10 @@ class SessionVerificationControllerProxy: SessionVerificationControllerProxyProt return .failure(.failedRequestingVerification) } } - .value } func approveVerification() async -> Result { - await Task.detached { + await Task.dispatch(on: .global()) { do { try self.sessionVerificationController.approveVerification() return .success(()) @@ -83,11 +82,10 @@ class SessionVerificationControllerProxy: SessionVerificationControllerProxyProt return .failure(.failedApprovingVerification) } } - .value } func declineVerification() async -> Result { - await Task.detached { + await Task.dispatch(on: .global()) { do { try self.sessionVerificationController.declineVerification() return .success(()) @@ -95,11 +93,10 @@ class SessionVerificationControllerProxy: SessionVerificationControllerProxyProt return .failure(.failedDecliningVerification) } } - .value } func cancelVerification() async -> Result { - await Task.detached { + await Task.dispatch(on: .global()) { do { try self.sessionVerificationController.cancelVerification() return .success(()) @@ -107,7 +104,6 @@ class SessionVerificationControllerProxy: SessionVerificationControllerProxyProt return .failure(.failedCancellingVerification) } } - .value } // MARK: - Private diff --git a/ElementX/Sources/Services/UserSessionStore/UserSessionStore.swift b/ElementX/Sources/Services/UserSessionStore/UserSessionStore.swift index 52c2432722..b024f213de 100644 --- a/ElementX/Sources/Services/UserSessionStore/UserSessionStore.swift +++ b/ElementX/Sources/Services/UserSessionStore/UserSessionStore.swift @@ -93,16 +93,14 @@ class UserSessionStore: UserSessionStoreProtocol { .basePath(path: baseDirectoryPath) .username(username: credentials.userID) - let loginTask: Task = Task.detached { - let client = try builder.build() - try client.restoreLogin(restoreToken: credentials.restoreToken) - return client - } - - switch await loginTask.result { - case .success(let client): + do { + let client: Client = try await Task.dispatch(on: .global()) { + let client = try builder.build() + try client.restoreLogin(restoreToken: credentials.restoreToken) + return client + } return await setupProxyForClient(client) - case .failure(let error): + } catch { MXLog.error("Failed restoring login with error: \(error)") return .failure(.failedRestoringLogin) } diff --git a/changelog.d/pr-201.bugfix b/changelog.d/pr-201.bugfix new file mode 100644 index 0000000000..9db3e190a4 --- /dev/null +++ b/changelog.d/pr-201.bugfix @@ -0,0 +1 @@ +Replace blocking detached tasks with Task.dispatch(on:).