【发布时间】:2022-01-15 15:05:47
【问题描述】:
我试图在应用开始后立即显示 Subscribe Now 模式视图,以鼓励用户订阅 Pro In-App Purchase,所以我使用了.onAppear 修饰符,它只有在我想在每次应用启动时都显示模式时才能正常工作。
struct ContentView: View {
@State private var selection: String? = nil
@State private var showModal = false
@ObservedObject var storeManager: StoreManager
var body: some View {
NavigationView {
VStack {
// Contents Here
}
}
.onAppear {
self.selection = "Pro"
self.showModal.toggle()
}
.sheet(isPresented: $showModal) {
if self.selection == "Pro" {
Pro(showModal: self.$showModal, storeManager: self.storeManager)
.onAppear(perform: {
SKPaymentQueue.default().add(storeManager)
})
}
}
}
}
现在,当我想向尚未订阅 Pro IAP 的人显示模式 only 时,问题就开始了,因此我将.onAppear 修改为:
.onAppear {
ForEach(storeManager.myProducts, id: \.self) { product in
VStack {
if !UserDefaults.standard.bool(forKey: product.productIdentifier) {
self.selection = "Pro"
self.showModal.toggle()
}
}
}
}
但是,if 和 ForEach 似乎不能顺利地与结构和视图一起使用。我应该如何使用它们?
更新:
根据答案,我更改了.onAppear 内的循环,以使代码符合SwiftUI 要求:
.onAppear {
storeManager.myProducts.forEach { product in
// Alternatively, I can use (for in) loop:
// for product in storeManager.myProducts {
if !UserDefaults.standard.bool(forKey: product.productIdentifier) {
self.selection = "Pro"
self.showModal.toggle()
}
}
}
现在,错误已经消失,但启动时不显示模式。
我发现问题是,storeManager.myProducts 没有加载到 .onAppear 修饰符中,而当我将相同的循环放入按钮而不是 .onAppear 时,它会正确加载,有什么想法吗?为什么 onAppear 不加载 IAP?当视图加载时,我应该将代码放在哪里以使模式运行?
更新 2:
这是一个最小的可重现示例:
应用:
import SwiftUI
@main
struct Reprod_SOFApp: App {
@StateObject var storeManager = StoreManager()
let productIDs = ["xxxxxxxxxxxxxxxxxxxxx"]
var body: some Scene {
DocumentGroup(newDocument: Reprod_SOFDocument()) { file in
ContentView(document: file.$document, storeManager: storeManager)
.onAppear() {
storeManager.getProducts(productIDs: productIDs)
}
}
}
}
内容视图:
import SwiftUI
import StoreKit
struct ContentView: View {
@Binding var document: Reprod_SOFDocument
@State private var selection: String? = nil
@State private var showModal = false
@ObservedObject var storeManager: StoreManager
var test = ["t"]
var body: some View {
TextEditor(text: $document.text)
.onAppear {
// storeManager.myProducts.forEach(id: \.self) { product in
// Alternatively, I can use (for in) loop:
for i in test {
if !i.isEmpty {
self.selection = "Pro"
self.showModal.toggle()
}
}
}
.sheet(isPresented: $showModal) {
if self.selection == "Pro" {
Modal(showModal: self.$showModal, storeManager: self.storeManager)
.onAppear(perform: {
SKPaymentQueue.default().add(storeManager)
})
}
}
}
}
模态:
import SwiftUI
import StoreKit
struct Modal: View {
@Binding var showModal: Bool
@ObservedObject var storeManager: StoreManager
var body: some View {
Text("hello world")
}
}
商店经理:
import Foundation
import StoreKit
class StoreManager: NSObject, ObservableObject, SKProductsRequestDelegate, SKPaymentTransactionObserver {
@Published var myProducts = [SKProduct]()
var request: SKProductsRequest!
@Published var transactionState: SKPaymentTransactionState?
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
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 productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
print("Did receive response")
if !response.products.isEmpty {
for fetchedProduct in response.products {
DispatchQueue.main.async {
self.myProducts.append(fetchedProduct)
}
}
}
for invalidIdentifier in response.invalidProductIdentifiers {
print("Invalid identifiers found: \(invalidIdentifier)")
}
}
func getProducts(productIDs: [String]) {
print("Start requesting products ...")
let request = SKProductsRequest(productIdentifiers: Set(productIDs))
request.delegate = self
request.start()
}
func request(_ request: SKRequest, didFailWithError error: Error) {
print("Request did fail: \(error)")
}
func purchaseProduct(product: SKProduct) {
if SKPaymentQueue.canMakePayments() {
let payment = SKPayment(product: product)
SKPaymentQueue.default().add(payment)
} else {
print("User can't make payment.")
}
}
func restoreProducts() {
print("Restoring products ...")
SKPaymentQueue.default().restoreCompletedTransactions()
}
}
【问题讨论】: