Skip to content

Commit

Permalink
Replace withCheckedThrowingContinuation Calls With withUnsafeThrowing…
Browse files Browse the repository at this point in the history
…Continuation (#4286)

* replace withCheckedThrowingContinuation calls with withUnsafeThrowingContinuation

* replaced instances of withCheckedContinuation -> withUnsafeContinuation

* update the links in comments to point to the issue not the PR

* linting

---------

Co-authored-by: andy boedo <andresboedo@gmail.com>
  • Loading branch information
2 people authored and nyeu committed Oct 1, 2024
1 parent 70b2ae5 commit ff14a7a
Show file tree
Hide file tree
Showing 9 changed files with 47 additions and 28 deletions.
7 changes: 5 additions & 2 deletions Sources/FoundationExtensions/AsyncExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ internal enum Async {
static func call<Value, Error: Swift.Error>(
method: (@escaping @Sendable (Result<Value, Error>) -> Void) -> Void
) async throws -> Value {
return try await withCheckedThrowingContinuation { continuation in
return try await withUnsafeThrowingContinuation { continuation in
@Sendable
func complete(_ result: Result<Value, Error>) {
continuation.resume(with: result)
Expand All @@ -101,7 +101,10 @@ internal enum Async {
static func call<Value>(
method: (@escaping @Sendable (Value) -> Void) -> Void
) async -> Value {
return await withCheckedContinuation { continuation in
// Note: We're using UnsafeContinuation instead of Checked because
// of a crash in iOS 18.0 devices when CheckedContinuations are used.
// See: https://github.com/RevenueCat/purchases-ios/issues/4177
return await withUnsafeContinuation { continuation in
@Sendable
func complete(_ value: Value) {
continuation.resume(with: .success(value))
Expand Down
36 changes: 20 additions & 16 deletions Sources/Misc/Concurrency/Purchases+async.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,14 @@ import Foundation
/// This extension holds the biolerplate logic to convert methods with completion blocks into async / await syntax.
extension Purchases {

// Note: We're using UnsafeContinuation instead of Checked because
// of a crash in iOS 18.0 devices when CheckedContinuations are used.
// See: https://github.com/RevenueCat/purchases-ios/issues/4177

#if !ENABLE_CUSTOM_ENTITLEMENT_COMPUTATION

func logInAsync(_ appUserID: String) async throws -> (customerInfo: CustomerInfo, created: Bool) {
return try await withCheckedThrowingContinuation { continuation in
return try await withUnsafeThrowingContinuation { continuation in
logIn(appUserID) { customerInfo, created, error in
continuation.resume(with: Result(customerInfo, error)
.map { ($0, created) })
Expand All @@ -28,15 +32,15 @@ extension Purchases {
}

func logOutAsync() async throws -> CustomerInfo {
return try await withCheckedThrowingContinuation { continuation in
return try await withUnsafeThrowingContinuation { continuation in
logOut { customerInfo, error in
continuation.resume(with: Result(customerInfo, error))
}
}
}

func syncAttributesAndOfferingsIfNeededAsync() async throws -> Offerings? {
return try await withCheckedThrowingContinuation { continuation in
return try await withUnsafeThrowingContinuation { continuation in
syncAttributesAndOfferingsIfNeeded { offerings, error in
continuation.resume(with: Result(offerings, error))
}
Expand All @@ -46,23 +50,23 @@ extension Purchases {
#endif

func offeringsAsync(fetchPolicy: OfferingsManager.FetchPolicy) async throws -> Offerings {
return try await withCheckedThrowingContinuation { continuation in
return try await withUnsafeThrowingContinuation { continuation in
self.getOfferings(fetchPolicy: fetchPolicy) { offerings, error in
continuation.resume(with: Result(offerings, error))
}
}
}

func productsAsync(_ productIdentifiers: [String]) async -> [StoreProduct] {
return await withCheckedContinuation { continuation in
return await withUnsafeContinuation { continuation in
getProducts(productIdentifiers) { result in
continuation.resume(returning: result)
}
}
}

func purchaseAsync(product: StoreProduct) async throws -> PurchaseResultData {
return try await withCheckedThrowingContinuation { continuation in
return try await withUnsafeThrowingContinuation { continuation in
purchase(product: product) { transaction, customerInfo, error, userCancelled in
continuation.resume(with: Result(customerInfo, error)
.map { PurchaseResultData(transaction, $0, userCancelled) })
Expand All @@ -71,7 +75,7 @@ extension Purchases {
}

func purchaseAsync(package: Package) async throws -> PurchaseResultData {
return try await withCheckedThrowingContinuation { continuation in
return try await withUnsafeThrowingContinuation { continuation in
purchase(package: package) { transaction, customerInfo, error, userCancelled in
continuation.resume(with: Result(customerInfo, error)
.map { PurchaseResultData(transaction, $0, userCancelled) })
Expand All @@ -80,7 +84,7 @@ extension Purchases {
}

func restorePurchasesAsync() async throws -> CustomerInfo {
return try await withCheckedThrowingContinuation { continuation in
return try await withUnsafeThrowingContinuation { continuation in
self.restorePurchases { customerInfo, error in
continuation.resume(with: Result(customerInfo, error))
}
Expand All @@ -90,15 +94,15 @@ extension Purchases {
#if !ENABLE_CUSTOM_ENTITLEMENT_COMPUTATION

func syncPurchasesAsync() async throws -> CustomerInfo {
return try await withCheckedThrowingContinuation { continuation in
return try await withUnsafeThrowingContinuation { continuation in
syncPurchases { customerInfo, error in
continuation.resume(with: Result(customerInfo, error))
}
}
}

func purchaseAsync(product: StoreProduct, promotionalOffer: PromotionalOffer) async throws -> PurchaseResultData {
return try await withCheckedThrowingContinuation { continuation in
return try await withUnsafeThrowingContinuation { continuation in
purchase(product: product,
promotionalOffer: promotionalOffer) { transaction, customerInfo, error, userCancelled in
continuation.resume(with: Result(customerInfo, error)
Expand All @@ -108,7 +112,7 @@ extension Purchases {
}

func purchaseAsync(package: Package, promotionalOffer: PromotionalOffer) async throws -> PurchaseResultData {
return try await withCheckedThrowingContinuation { continuation in
return try await withUnsafeThrowingContinuation { continuation in
purchase(package: package,
promotionalOffer: promotionalOffer) { transaction, customerInfo, error, userCancelled in
continuation.resume(with: Result(customerInfo, error)
Expand All @@ -118,7 +122,7 @@ extension Purchases {
}

func customerInfoAsync(fetchPolicy: CacheFetchPolicy) async throws -> CustomerInfo {
return try await withCheckedThrowingContinuation { continuation in
return try await withUnsafeThrowingContinuation { continuation in
getCustomerInfo(fetchPolicy: fetchPolicy) { customerInfo, error in
continuation.resume(with: Result(customerInfo, error))
}
Expand All @@ -127,7 +131,7 @@ extension Purchases {

func checkTrialOrIntroductoryDiscountEligibilityAsync(_ product: StoreProduct) async
-> IntroEligibilityStatus {
return await withCheckedContinuation { continuation in
return await withUnsafeContinuation { continuation in
checkTrialOrIntroDiscountEligibility(product: product) { status in
continuation.resume(returning: status)
}
Expand All @@ -136,7 +140,7 @@ extension Purchases {

func checkTrialOrIntroductoryDiscountEligibilityAsync(_ productIdentifiers: [String]) async
-> [String: IntroEligibility] {
return await withCheckedContinuation { continuation in
return await withUnsafeContinuation { continuation in
checkTrialOrIntroDiscountEligibility(productIdentifiers: productIdentifiers) { result in
continuation.resume(returning: result)
}
Expand All @@ -145,7 +149,7 @@ extension Purchases {

func promotionalOfferAsync(forProductDiscount discount: StoreProductDiscount,
product: StoreProduct) async throws -> PromotionalOffer {
return try await withCheckedThrowingContinuation { continuation in
return try await withUnsafeThrowingContinuation { continuation in
getPromotionalOffer(forProductDiscount: discount, product: product) { offer, error in
continuation.resume(with: Result(offer, error))
}
Expand Down Expand Up @@ -197,7 +201,7 @@ extension Purchases {
@available(watchOS, unavailable)
@available(tvOS, unavailable)
func showManageSubscriptionsAsync() async throws {
return try await withCheckedThrowingContinuation { continuation in
return try await withUnsafeThrowingContinuation { continuation in
showManageSubscriptions { error in
if let error = error {
continuation.resume(throwing: error)
Expand Down
10 changes: 8 additions & 2 deletions Sources/Purchasing/ReceiptFetcher.swift
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,10 @@ class ReceiptFetcher {
}

func receiptData(refreshPolicy: ReceiptRefreshPolicy) async -> Data? {
return await withCheckedContinuation { continuation in
// Note: We're using UnsafeContinuation instead of Checked because
// of a crash in iOS 18.0 devices when CheckedContinuations are used.
// See: https://github.com/RevenueCat/purchases-ios/issues/4177
return await withUnsafeContinuation { continuation in
self.receiptData(refreshPolicy: refreshPolicy) { result, _ in
continuation.resume(returning: result)
}
Expand Down Expand Up @@ -155,7 +158,10 @@ private extension ReceiptFetcher {

/// `async` version of `refreshReceipt(_:)`
func refreshReceipt() async -> (Data, URL?) {
await withCheckedContinuation { continuation in
// Note: We're using UnsafeContinuation instead of Checked because
// of a crash in iOS 18.0 devices when CheckedContinuations are used.
// See: https://github.com/RevenueCat/purchases-ios/issues/4177
await withUnsafeContinuation { continuation in
self.refreshReceipt {
continuation.resume(returning: ($0, $1))
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ final class ExternalPurchasesManager: NSObject {
extension ExternalPurchasesManager {

func purchase(sk1Product product: SK1Product) async throws -> SK1PurchaseCompletedResult {
return try await withCheckedThrowingContinuation { continuation in
return try await withUnsafeThrowingContinuation { continuation in
self.purchase(sk1Product: product) { transaction in
if let error = transaction.error {
continuation.resume(throwing: error)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ final class SK1ProductFetcher: NSObject {
}

func products(with identifiers: Set<String>) async throws -> Set<SK1Product> {
return try await withCheckedThrowingContinuation { continuation in
return try await withUnsafeThrowingContinuation { continuation in
self.products(with: identifiers) { result in
continuation.resume(with: result)
}
Expand Down
5 changes: 4 additions & 1 deletion Tests/RevenueCatUITests/ImageLoaderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,10 @@ private final class MockAsyncURLSession: NSObject, URLSessionType {
self.completionSet = false
self.completion = nil

return try await withCheckedContinuation { continuation in
// Note: We're using UnsafeContinuation instead of Checked because
// of a crash in iOS 18.0 devices when CheckedContinuations are used.
// See: https://github.com/RevenueCat/purchases-ios/issues/4177
return try await withUnsafeContinuation { continuation in
self.completion = { value in
continuation.resume(returning: value)
}
Expand Down
7 changes: 5 additions & 2 deletions Tests/RevenueCatUITests/Purchasing/PurchaseHandlerTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,10 @@ class PurchaseHandlerTests: TestCase {
@available(iOS 15.0, macOS 12.0, tvOS 15.0, watchOS 8.0, *)
private final class AsyncPurchaseHandler {

var continuation: CheckedContinuation<Void, Never>?
// Note: We're using UnsafeContinuation instead of Checked because
// of a crash in iOS 18.0 devices when CheckedContinuations are used.
// See: https://github.com/RevenueCat/purchases-ios/issues/4177
var continuation: UnsafeContinuation<Void, Never>?
private(set) var purchaseHandler: PurchaseHandler!

init() {
Expand Down Expand Up @@ -260,7 +263,7 @@ private final class AsyncPurchaseHandler {
}

private func createAndWaitForContinuation() async {
await withCheckedContinuation { [weak self] continuation in
await withUnsafeContinuation { [weak self] continuation in
self?.continuation = continuation
}
}
Expand Down
4 changes: 2 additions & 2 deletions Tests/StoreKitUnitTests/PurchasesOrchestratorSK1Tests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ class PurchasesOrchestratorSK1Tests: BasePurchasesOrchestratorTests, PurchasesOr
payment.productIdentifier = ""

let (transaction, customerInfo, error, cancelled) =
try await withCheckedThrowingContinuation { continuation in
try await withUnsafeThrowingContinuation { continuation in
self.orchestrator.purchase(
sk1Product: product,
payment: payment,
Expand All @@ -287,7 +287,7 @@ class PurchasesOrchestratorSK1Tests: BasePurchasesOrchestratorTests, PurchasesOr
let payment = self.storeKit1Wrapper.payment(with: product)
self.receiptFetcher.shouldReturnReceipt = false

let (_, _, error, _) = try await withCheckedThrowingContinuation { continuation in
let (_, _, error, _) = try await withUnsafeThrowingContinuation { continuation in
self.orchestrator.purchase(
sk1Product: product,
payment: payment,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ final class ProductFetcherSK1: NSObject {
}

func products(with identifiers: Set<String>) async throws -> Set<SK1Product> {
return try await withCheckedThrowingContinuation { continuation in
return try await withUnsafeThrowingContinuation { continuation in
self.products(with: identifiers) { result in
continuation.resume(with: result)
}
Expand Down

0 comments on commit ff14a7a

Please sign in to comment.