StoreKit自动续订订阅可选类型赋值错误求助
StoreKit自动续订订阅可选类型不匹配问题修复
问题描述
基于Apple的StoreKit示例实现自动续订订阅,已将示例重构为仅包含年度订阅并上传至Github,但将代码复制到个人Xcode项目后,出现两处可选类型层级不匹配的赋值错误:
- Store类第214行:
subscriptionGroupStatus = try? await subscriptions.first?.subscription?.status.first?.state
错误提示:无法将Product.SubscriptionInfo.RenewalState??类型赋值给RenewalState?类型 - StatusInfoView第134行:
subscriptionStatus = try? await product.subscription?.status.last
错误提示:无法将Product.SubscriptionInfo.Status??类型赋值给Product.SubscriptionInfo.Status?类型
原Github项目无此错误,需修复该赋值问题。
相关代码片段:
@MainActor func updateCustomerProductStatus() async { var purchasedSubscriptions: [Product] = [] //Iterate through all of the user's purchased products. for await result in Transaction.currentEntitlements { do { //Check whether the transaction is verified. If it isn’t, catch `failedVerification` error. let transaction = try checkVerified(result) //Check the `productType` of the transaction and get the corresponding product from the store. switch transaction.productType { case .autoRenewable: if let subscription = subscriptions.first(where: { $0.id == transaction.productID }) { purchasedSubscriptions.append(subscription) } default: break } } catch { print() } } //Update the store information with auto-renewable subscription products. self.purchasedSubscriptions = purchasedSubscriptions //Check the `subscriptionGroupStatus` to learn the auto-renewable subscription state to determine whether the customer //is new (never subscribed), active, or inactive (expired subscription). This app has only one subscription //group, so products in the subscriptions array all belong to the same group. The statuses that //`product.subscription.status` returns apply to the entire subscription group. //let storeProducts = try await Product.products(for: productIdToEmoji.keys) subscriptionGroupStatus = try? await subscriptions.first?.subscription?.status.first?.state } struct StatusInfoView_Previews: PreviewProvider { @StateObject static var store = Store() @State static var subscription: Product? @State static var subscriptionStatus: Product.SubscriptionInfo.Status? static var previews: some View { Group { if let subscription, let subscriptionStatus { StatusInfoView(product: subscription, status: subscriptionStatus) .environmentObject(store) } } .task { guard let product = store.purchasedSubscriptions.first else { return } subscription = product subscriptionStatus = try? await product.subscription?.status.last } } }
解决方案
这两个错误的核心原因是嵌套可选链+try? await导致的双重可选类型:try? await会将异步调用结果包装为可选类型,再叠加前面的?.可选链,最终生成??类型,与目标变量的?类型不兼容。以下是两种修复方式:
1. 修复Store类的赋值错误
方式一:分步解包(可读性更高)
// 替换原有的单行赋值代码 if let firstSubscription = subscriptions.first, let subscriptionInfo = firstSubscription.subscription { do { let statuses = try await subscriptionInfo.status subscriptionGroupStatus = statuses.first?.state } catch { subscriptionGroupStatus = nil } } else { subscriptionGroupStatus = nil }
方式二:flatMap简化(保持单行风格)
subscriptionGroupStatus = try? await subscriptions.first?.subscription?.status.flatMap { $0.first?.state }
2. 修复StatusInfoView的赋值错误
方式一:分步解包(可读性更高)
// 替换原有的单行赋值代码 if let subscriptionInfo = product.subscription { do { let statuses = try await subscriptionInfo.status subscriptionStatus = statuses.last } catch { subscriptionStatus = nil } } else { subscriptionStatus = nil }
方式二:flatMap简化(保持单行风格)
subscriptionStatus = try? await product.subscription?.status.flatMap { $0.last }
额外说明
原Github项目无此错误,大概率是因为项目中subscriptions数组确保非空、subscription属性一定存在,可选链层级更少。而你的项目中这些值均为可选状态,再加上try? await的包装,才产生了双重可选类型。通过分步解包或flatMap可以将双重可选降为单层可选,与目标变量类型匹配。
内容的提问来源于stack exchange,提问作者Rami Ammoun
相关产品推荐
相关产品推荐

