final class IAPManager: NSObject, SKProductsRequestDelegate, SKPaymentTransactionObserver { static let shared = IAPManager() private var products = [SKProduct]() private var completion: (() -> Void)? private var productBeingPurchased: SKProduct? enum Product: String, CaseIterable { case removeAds = "JokesRUs.RemoveAds1" case summerIcon = "JokesRUs.Icons.Summer" case tacoIcon = "JokesRUs.Icons.Taco" case pizzaIcon = "JokesRUs.Icons.Pizza" case hotdogIcon = "JokesRUs.Icons.HotDog" case hamburgerIcon = "JokesRUs.Icons.Hamburger" case doughnutIcon = "JokesRUs.Icons.Doughnut" case support1 = "JokesRUs.Support.One" case support5 = "JokesRUs.Support.Five" case support10 = "JokesRUs.Support.Ten" case support20 = "JokesRUs.Support.Twenty" } let group = DispatchGroup() public func fetchProducts() { let request = SKProductsRequest(productIdentifiers: Set(Product.allCases.compactMap(({ $0.rawValue })))) request.delegate = self request.start() } func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) { print("products returned = \(response.products.count )") products = response.products } func request(_ request: SKRequest, didFailWithError error: Error) { guard request is SKProductsRequest else { return } print("Product fetch request failed") } public func purchase(product: Product, completion: @escaping (() -> Void)) { print("product = \(product)") print("can make payments = \(SKPaymentQueue.canMakePayments())") guard SKPaymentQueue.canMakePayments() else { return } print("product = \(product.rawValue)") guard let storeKitProduct = products.first(where: { $0.productIdentifier == product.rawValue }) else { return } Utilities.purchaseFailed = false print("call purchase") let paymentRequest = SKPayment(product: storeKitProduct) SKPaymentQueue.default().add(self) SKPaymentQueue.default().add(paymentRequest) print("Payments pending = \(SKPaymentQueue.default().transactions)") completion() // self.completion = completion }