swift - 存储在 CoreData 中的应用内购买回调函数
问题描述
我有一个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()
}
}
一切正常,购买发生。但我无法让关键的事情发挥作用。当它处于模式时,我如何在内部等待ContentView
回调?我考虑过并想在这样的函数中使用它:paymentQueue
.purchased
@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()
函数之后立即运行并且不会触发。我知道寻找的正确时机是在StoreManager
at the内部case .purchased
。但我不能EnvironmentObject
在那里使用我的。我对 Swift 比较陌生,所以我可能在这里缺少关于回调、状态或触发函数的关键特性。
解决方案
这个答案为我指明了正确的方向:当状态发生变化时,我如何运行一个动作?
我将我的按钮更改ContentView
为:
Button(action: {
purchaseAndSaveToCoreData()
}, label: {
Text("buy for 100")
})
.onChange(of: storeManager.transactionState) { transactionState in
if transactionState == .purchased {
saveVirginKeyToCoreData()
}
}
该onChange
属性监听 的状态变化transactionState
。
推荐阅读
- javascript - javascript读取对象的位置并通过onclick显示,或保存在变量中
- php - Laravel - 某些表的数据未获取
- c++ - Qt connect 有效,等效的断开方法是什么?
- r - 在R中将png转换为svg?
- flutter - Flutter:如何在 ListView 中添加更多按钮
- xml - 元素类型“”的内容必须在xml中匹配
- sql-server - SQL Server 替换整个未知字符串列
- python - 在一个屏幕上运行一个 kivy 应用程序,对于按下的任何键盘按钮,我可以键入 TextInput 小部件吗?
- arrays - angular.copy() 不复制数组和选择排序不起作用
- ios - 如何在 swift 5 中将数据从模态呈现的 ViewController 传递给父 ViewController?