Skip to content

Commit

Permalink
Async.call method to convert completion-block call to async (#1969)
Browse files Browse the repository at this point in the history
This simplifies calling completion-block APIs as `async`. The opposite
of what #1943 introduced.
  • Loading branch information
NachoSoto authored Oct 10, 2022
1 parent 6785b6e commit b981e0f
Show file tree
Hide file tree
Showing 8 changed files with 60 additions and 33 deletions.
13 changes: 13 additions & 0 deletions Sources/FoundationExtensions/AsyncExtensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,17 @@ 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
@Sendable
func complete(_ result: Result<Value, Error>) {
continuation.resume(with: result)
}

method(complete)
}
}

}
12 changes: 4 additions & 8 deletions Sources/Purchasing/ProductsManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -139,20 +139,16 @@ extension ProductsManagerType {
/// `async` overload for `products(withIdentifiers:)`
@available(iOS 13.0, tvOS 13.0, watchOS 6.2, macOS 10.15, *)
func products(withIdentifiers identifiers: Set<String>) async throws -> Set<StoreProduct> {
return try await withCheckedThrowingContinuation { continuation in
self.products(withIdentifiers: identifiers) { result in
continuation.resume(with: result)
}
return try await Async.call { completion in
self.products(withIdentifiers: identifiers, completion: completion)
}
}

/// `async` overload for `sk2Products(withIdentifiers:)`
@available(iOS 15.0, tvOS 15.0, watchOS 8.0, macOS 12.0, *)
func sk2Products(withIdentifiers identifiers: Set<String>) async throws -> Set<SK2StoreProduct> {
return try await withCheckedThrowingContinuation { continuation in
self.sk2Products(withIdentifiers: identifiers) { result in
continuation.resume(with: result)
}
return try await Async.call { completion in
self.sk2Products(withIdentifiers: identifiers, completion: completion)
}
}

Expand Down
14 changes: 6 additions & 8 deletions Sources/Purchasing/Purchases/PurchasesOrchestrator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -466,11 +466,10 @@ final class PurchasesOrchestrator {
forProductDiscount discount: StoreProductDiscountType,
product: StoreProductType
) async throws -> PromotionalOffer {
return try await withCheckedThrowingContinuation { continuation in
return try await Async.call { completion in
self.promotionalOffer(forProductDiscount: discount,
product: product) { result in
continuation.resume(with: result)
}
product: product,
completion: completion)
}
}

Expand Down Expand Up @@ -1095,12 +1094,11 @@ extension PurchasesOrchestrator {
func syncPurchases(receiptRefreshPolicy: ReceiptRefreshPolicy,
isRestore: Bool,
initiationSource: ProductRequestData.InitiationSource) async throws -> CustomerInfo {
return try await withCheckedThrowingContinuation { continuation in
return try await Async.call { completion in
self.syncPurchases(receiptRefreshPolicy: receiptRefreshPolicy,
isRestore: isRestore,
initiationSource: initiationSource) { result in
continuation.resume(with: result)
}
initiationSource: initiationSource,
completion: completion)
}
}

Expand Down
6 changes: 2 additions & 4 deletions Sources/Purchasing/StoreKit1/ProductsFetcherSK1.swift
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,8 @@ final class ProductsFetcherSK1: NSObject {

@available(iOS 13.0, macOS 10.15, tvOS 13.0, watchOS 6.2, *)
func products(withIdentifiers identifiers: Set<String>) async throws -> Set<SK1StoreProduct> {
return try await withCheckedThrowingContinuation { continuation in
self.products(withIdentifiers: identifiers) { result in
continuation.resume(with: result)
}
return try await Async.call { completion in
self.products(withIdentifiers: identifiers, completion: completion)
}
}

Expand Down
6 changes: 2 additions & 4 deletions Tests/StoreKitUnitTests/OfferingsManagerStoreKitTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,8 @@ private extension OfferingsManager {

@available(iOS 13.0, tvOS 13.0, watchOS 6.2, macOS 10.15, *)
func offerings(appUserID: String) async throws -> Offerings {
return try await withCheckedThrowingContinuation { continuation in
self.offerings(appUserID: appUserID) { result in
continuation.resume(with: result)
}
return try await Async.call { completion in
self.offerings(appUserID: appUserID, completion: completion)
}
}

Expand Down
7 changes: 3 additions & 4 deletions Tests/StoreKitUnitTests/PurchasesOrchestratorTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -211,11 +211,10 @@ class PurchasesOrchestratorTests: StoreKitConfigTestCase {
numberOfPeriods: 2,
type: .promotional)

_ = try await withCheckedThrowingContinuation { continuation in
_ = try await Async.call { completion in
orchestrator.promotionalOffer(forProductDiscount: storeProductDiscount,
product: StoreProduct(sk1Product: product)) { result in
continuation.resume(with: result)
}
product: StoreProduct(sk1Product: product),
completion: completion)
}

expect(self.offerings.invokedPostOfferCount) == 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ class TrialOrIntroPriceEligibilityCheckerSK2Tests: StoreKitConfigTestCase {

let storeProduct = try await self.fetchSk2StoreProduct()

let status: IntroEligibilityStatus = try await withCheckedThrowingContinuation { continuation in
let status: IntroEligibilityStatus = await withCheckedContinuation { continuation in
self.trialOrIntroPriceEligibilityChecker.checkEligibility(product: storeProduct) { status in
continuation.resume(returning: status)
}
Expand All @@ -159,7 +159,7 @@ class TrialOrIntroPriceEligibilityCheckerSK2Tests: StoreKitConfigTestCase {

let storeProduct = try await self.fetchSk2StoreProduct("lifetime")

let status: IntroEligibilityStatus = try await withCheckedThrowingContinuation { continuation in
let status: IntroEligibilityStatus = await withCheckedContinuation { continuation in
self.trialOrIntroPriceEligibilityChecker.checkEligibility(product: storeProduct) { status in
continuation.resume(returning: status)
}
Expand All @@ -175,7 +175,7 @@ class TrialOrIntroPriceEligibilityCheckerSK2Tests: StoreKitConfigTestCase {
let sk2Product = try await self.fetchSk2Product()
let storeProduct = StoreProduct(sk2Product: sk2Product)

let prePurchaseStatus: IntroEligibilityStatus = try await withCheckedThrowingContinuation { continuation in
let prePurchaseStatus: IntroEligibilityStatus = await withCheckedContinuation { continuation in
self.trialOrIntroPriceEligibilityChecker.checkEligibility(product: storeProduct) { status in
continuation.resume(returning: status)
}
Expand All @@ -185,7 +185,7 @@ class TrialOrIntroPriceEligibilityCheckerSK2Tests: StoreKitConfigTestCase {

_ = try await sk2Product.purchase()

let postPurchaseStatus: IntroEligibilityStatus = try await withCheckedThrowingContinuation { continuation in
let postPurchaseStatus: IntroEligibilityStatus = await withCheckedContinuation { continuation in
self.trialOrIntroPriceEligibilityChecker.checkEligibility(product: storeProduct) { status in
continuation.resume(returning: status)
}
Expand All @@ -203,7 +203,7 @@ class TrialOrIntroPriceEligibilityCheckerSK2Tests: StoreKitConfigTestCase {
// We can't fetch an invalid StoreProduct to pass into the
// eligibility checker so this just fakes an unknown response,
// regardless of the real status from the checker
let fakeStatus: IntroEligibilityStatus = try await withCheckedThrowingContinuation { continuation in
let fakeStatus: IntroEligibilityStatus = await withCheckedContinuation { continuation in
self.trialOrIntroPriceEligibilityChecker.checkEligibility(product: storeProduct) { _ in
continuation.resume(returning: .unknown)
}
Expand Down
25 changes: 25 additions & 0 deletions Tests/UnitTests/FoundationExtensions/AsyncExtensionsTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,29 @@ class AsyncExtensionsTests: TestCase {
expect(result).toEventually(equal(expected))
}

func testConversionToAsyncWithValue() async throws {
let expected = Int.random(in: 0..<100)

let result = try await Async.call { (completion: (Result<Int, NSError>) -> Void) in
completion(.success(expected))
}

expect(result) == expected
}

func testConversionToAsyncWithError() async throws {
enum Error: Swift.Error {
case error1
}

do {
let _: Int = try await Async.call { completion in
completion(.failure(Error.error1))
}
fail("Expected error")
} catch {
expect(error).to(matchError(Error.error1))
}
}

}

0 comments on commit b981e0f

Please sign in to comment.