From df78aa514e9c39ad2ded08a70ce3fb3296b7856c Mon Sep 17 00:00:00 2001 From: Anders Ha Date: Wed, 18 Sep 2024 23:03:33 +0100 Subject: [PATCH] VIT-7468: Workaround iOS 18 CheckedContinuation crash (#244) --- Sources/VitalCore/Core/Client/ProtectedBox.swift | 6 +++--- Sources/VitalCore/JWT/VitalJWTAuth.swift | 6 +++--- .../VitalDevices/DeviceReading/Libre1Reader.swift | 4 ++-- Sources/VitalDevices/NFC/NFC.swift | 4 ++-- Sources/VitalHealthKit/HealthKit/Abstractions.swift | 8 ++++---- Tests/VitalCoreTests/VitalClientTests.swift | 12 ++++++------ 6 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Sources/VitalCore/Core/Client/ProtectedBox.swift b/Sources/VitalCore/Core/Client/ProtectedBox.swift index 31050a2d..a32bdf90 100644 --- a/Sources/VitalCore/Core/Client/ProtectedBox.swift +++ b/Sources/VitalCore/Core/Client/ProtectedBox.swift @@ -37,7 +37,7 @@ public final class ProtectedBox: @unchecked Sendable { /// Get the current value, or wait until it is set. public func get() async -> T { - return await withCheckedContinuation { continuation in + return await withUnsafeContinuation { continuation in lock.withLock { switch self.state { case let .awaiting(continuations): @@ -50,7 +50,7 @@ public final class ProtectedBox: @unchecked Sendable { } public func set(value: T) { - let continuationsToCall: [CheckedContinuation] = lock.withLock { + let continuationsToCall: [UnsafeContinuation] = lock.withLock { defer { self.state = .ready(value) } @@ -84,7 +84,7 @@ public final class ProtectedBox: @unchecked Sendable { private enum BoxState { case ready(T) - case awaiting([CheckedContinuation]) + case awaiting([UnsafeContinuation]) var isReady: Bool { switch self { diff --git a/Sources/VitalCore/JWT/VitalJWTAuth.swift b/Sources/VitalCore/JWT/VitalJWTAuth.swift index bf95e296..9571ae6b 100644 --- a/Sources/VitalCore/JWT/VitalJWTAuth.swift +++ b/Sources/VitalCore/JWT/VitalJWTAuth.swift @@ -476,7 +476,7 @@ internal struct VitalSignInTokenClaims: Decodable { @_spi(VitalSDKInternals) public final class ParkingLot: @unchecked Sendable { enum State: Sendable { - case mustPark([UUID: CheckedContinuation] = [:]) + case mustPark([UUID: UnsafeContinuation] = [:]) case disabled } @@ -495,7 +495,7 @@ public final class ParkingLot: @unchecked Sendable { public init() {} public func tryTo(_ action: Action) -> Bool { - let (callersToRelease, hasTransitioned): ([CheckedContinuation], Bool) = lock.withLock { + let (callersToRelease, hasTransitioned): ([UnsafeContinuation], Bool) = lock.withLock { switch (self.state, action) { case (.disabled, .enable): self.state = .mustPark() @@ -525,7 +525,7 @@ public final class ParkingLot: @unchecked Sendable { return try await withTaskCancellationHandler { try Task.checkCancellation() - return try await withCheckedThrowingContinuation { continuation in + return try await withUnsafeThrowingContinuation { continuation in let mustPark = lock.withLock { switch self.state { case let .mustPark(parked): diff --git a/Sources/VitalDevices/DeviceReading/Libre1Reader.swift b/Sources/VitalDevices/DeviceReading/Libre1Reader.swift index bbf6b16c..b8fc4d3b 100644 --- a/Sources/VitalDevices/DeviceReading/Libre1Reader.swift +++ b/Sources/VitalDevices/DeviceReading/Libre1Reader.swift @@ -21,10 +21,10 @@ public class Libre1Reader { } public func read() async throws -> (Libre1Read) { - /// We need to retain the NFC object, otherwise it's released inside `withCheckedThrowingContinuation` + /// We need to retain the NFC object, otherwise it's released inside `withUnsafeThrowingContinuation` var nfc: NFC! - let payload: (Sensor, [Glucose]) = try await withCheckedThrowingContinuation { continuation in + let payload: (Sensor, [Glucose]) = try await withUnsafeThrowingContinuation { continuation in nfc = NFC( readingMessage: readingMessage, errorMessage: errorMessage, diff --git a/Sources/VitalDevices/NFC/NFC.swift b/Sources/VitalDevices/NFC/NFC.swift index d5fc0264..6f58bf03 100644 --- a/Sources/VitalDevices/NFC/NFC.swift +++ b/Sources/VitalDevices/NFC/NFC.swift @@ -121,7 +121,7 @@ class NFC: NSObject, NFCTagReaderSessionDelegate { let readingMessage: String let errorMessage: String let completionMessage: String - private var continuation: CheckedContinuation<(Sensor, [Glucose]), Error>? + private var continuation: UnsafeContinuation<(Sensor, [Glucose]), Error>? private let queue: DispatchQueue var taskRequest: TaskRequest? { @@ -139,7 +139,7 @@ class NFC: NSObject, NFCTagReaderSessionDelegate { readingMessage: String, errorMessage: String, completionMessage: String, - continuation: CheckedContinuation<(Sensor, [Glucose]), Error>?, + continuation: UnsafeContinuation<(Sensor, [Glucose]), Error>?, queue: DispatchQueue ) { self.readingMessage = readingMessage diff --git a/Sources/VitalHealthKit/HealthKit/Abstractions.swift b/Sources/VitalHealthKit/HealthKit/Abstractions.swift index f09ff68a..c0fb8161 100644 --- a/Sources/VitalHealthKit/HealthKit/Abstractions.swift +++ b/Sources/VitalHealthKit/HealthKit/Abstractions.swift @@ -567,7 +567,7 @@ final class CancellableQueryHandle: @unchecked Sendable { case idle case cancelled case completed - case running(HKHealthStore, HKQuery, CheckedContinuation) + case running(HKHealthStore, HKQuery, UnsafeContinuation) } private var state: State = .idle @@ -589,7 +589,7 @@ final class CancellableQueryHandle: @unchecked Sendable { try await withTaskCancellationHandler { try Task.checkCancellation() - let result = try await withCheckedThrowingContinuation { continuation in + let result = try await withUnsafeThrowingContinuation { continuation in let query = queryFactory(Continuation(query: self)) transition(to: .running(store, query, continuation)) } @@ -608,8 +608,8 @@ final class CancellableQueryHandle: @unchecked Sendable { } @discardableResult - private func transition(to newState: State) -> CheckedContinuation? { - let (doWork, continuation): ((() -> Void)?, CheckedContinuation?) = lock.withLock { + private func transition(to newState: State) -> UnsafeContinuation? { + let (doWork, continuation): ((() -> Void)?, UnsafeContinuation?) = lock.withLock { switch (state, newState) { case let (.idle, .running(store, query, _)): diff --git a/Tests/VitalCoreTests/VitalClientTests.swift b/Tests/VitalCoreTests/VitalClientTests.swift index 0d088921..f75b26a1 100644 --- a/Tests/VitalCoreTests/VitalClientTests.swift +++ b/Tests/VitalCoreTests/VitalClientTests.swift @@ -68,7 +68,7 @@ class VitalClientTests: XCTestCase { } func testAutomaticConfiguration_autoMigrateFromLegacyAPIMode() async throws { - let _: Void = await withCheckedContinuation { continuation in + let _: Void = await withUnsafeContinuation { continuation in VitalClient.automaticConfiguration { continuation.resume(returning: ()) } @@ -98,7 +98,7 @@ class VitalClientTests: XCTestCase { let newClient = VitalClient(secureStorage: secureStorage) VitalClient.setClient(newClient) - let _: Void = await withCheckedContinuation { continuation in + let _: Void = await withUnsafeContinuation { continuation in VitalClient.automaticConfiguration { continuation.resume(returning: ()) } @@ -115,7 +115,7 @@ class VitalClientTests: XCTestCase { } func testAutomaticConfiguration_userJWTMode() async throws { - let _: Void = await withCheckedContinuation { continuation in + let _: Void = await withUnsafeContinuation { continuation in VitalClient.automaticConfiguration { continuation.resume(returning: ()) } @@ -142,7 +142,7 @@ class VitalClientTests: XCTestCase { let newClient = VitalClient(secureStorage: secureStorage) VitalClient.setClient(newClient) - let _: Void = await withCheckedContinuation { continuation in + let _: Void = await withUnsafeContinuation { continuation in VitalClient.automaticConfiguration { continuation.resume(returning: ()) } @@ -159,7 +159,7 @@ class VitalClientTests: XCTestCase { } func testAutoConfigurationDoesNotFailWithUserIdWithoutConfiguration() async { - let _: Void = await withCheckedContinuation { continuation in + let _: Void = await withUnsafeContinuation { continuation in VitalClient.automaticConfiguration { continuation.resume(returning: ()) } @@ -176,7 +176,7 @@ class VitalClientTests: XCTestCase { let newClient = VitalClient(secureStorage: secureStorage) VitalClient.setClient(newClient) - let _: Void = await withCheckedContinuation { continuation in + let _: Void = await withUnsafeContinuation { continuation in VitalClient.automaticConfiguration { continuation.resume(returning: ()) }