You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 02:35:18