【发布时间】:2021-02-11 19:36:26
【问题描述】:
我有一个ContentView,它使用EnvironmentObject。应用内购买后,此对象应保存到CoreData。我的ContentView 看起来像这样:
//ContentView
import SwiftUI
struct ContentView: View {
@EnvironmentObject var modelData: ModelData
@Environment(\.managedObjectContext) private var viewContext
@StateObject var storeManager: StoreManager
var body: some View {
Button(action: {
purchaseAndSaveToCoreData()
}, label: {
Text("buy for 100")
})
}
func purchaseAndSaveToCoreData() {
//Open the storeManager and do the purchase
storeManager.purchaseProduct(product: storeManager.myProducts[0])
//Wait for the purchase callback and then save an object from the EnvironmentObject modelData to CoreData here <- How?
let newItemToStore = Item(context: viewContext)
newItemToStore.name = modelData.name
do {
try viewContext.save()
} catch {
print(error.localizedDescription)
}
}
}
我的StoreManager 课程是这样的:
//StoreManager
import Foundation
import StoreKit
class StoreManager: NSObject, ObservableObject, SKProductsRequestDelegate, SKPaymentTransactionObserver {
//FETCH PRODUCTS
//[...] Fetching Process goes here
//HANDLE TRANSACTIONS
@Published var transactionState: SKPaymentTransactionState?
func purchaseProduct(product: SKProduct) {
if SKPaymentQueue.canMakePayments() {
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment)
} else {
print("User can't make payment.")
}
}
func paymentQueue(_ queue: SKPaymentQueue, updatedTransactions transactions: [SKPaymentTransaction]) {
for transaction in transactions {
switch transaction.transactionState {
case .purchasing:
transactionState = .purchasing
case .purchased:
UserDefaults.standard.setValue(true, forKey: transaction.payment.productIdentifier)
queue.finishTransaction(transaction)
transactionState = .purchased
//Can I use my environmentObject modelData here?
case .restored:
UserDefaults.standard.setValue(true, forKey: transaction.payment.productIdentifier)
queue.finishTransaction(transaction)
transactionState = .restored
case .failed, .deferred:
print("Payment Queue Error: \(String(describing: transaction.error))")
queue.finishTransaction(transaction)
transactionState = .failed
default:
queue.finishTransaction(transaction)
}
}
}
func restoreProducts() {
print("Restoring products ...")
SKPaymentQueue.default().restoreCompletedTransactions()
}
}
一切正常,购买成功。但我无法让关键的事情发挥作用。当它处于.purchased 模式时,如何在ContentView 内等待paymentQueue 的回调?
我想到了@Published transactionState 并想在purchaseAndSaveToCoreData() 函数中使用它,如下所示:
//ContentView
//[...]
storeManager.purchaseProduct(product: storeManager.myProducts[0])
//Wait for the purchase callback and then save an object from the EnvironmentObject modelData to CoreData here <- How?
if storeManager.transactionState == .purchased {
let newItemToStore = Item(context: viewContext)
newItemToStore.name = modelData.name
do {
try viewContext.save()
} catch {
print(error.localizedDescription)
}
}
但是if 语句当然会在storeManager.purchaseProduct() 函数之后立即运行并且不会触发。我知道寻找的正确时机是在case .purchased 的StoreManager 内。但我不能在那里使用我的EnvironmentObject。我对 Swift 比较陌生,所以我可能在这里缺少关于回调、状态或触发函数的关键特性。
【问题讨论】:
标签: swift swiftui in-app-purchase