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

Segue/实例化Stripe CheckoutViewController时初始化错误及数据传递问题求助

解决Stripe CheckoutViewController关联Storyboard后的初始化错误及数据传递问题

看起来你遇到的问题核心是Storyboard初始化ViewController时会调用init?(coder:),而这个方法的初始化逻辑没有符合Swift的存储属性初始化规则。让我一步步帮你理清问题并给出解决方案:

为什么会出现这些错误?

  1. 第一个错误:init(coder:) has not been implemented
    当你把ViewController关联到Storyboard后,系统会通过init?(coder:)来初始化这个VC,而你最初的实现里这个方法只是简单调用了super.init(coder:),没有初始化config这个let类型的存储属性——Swift要求所有存储属性必须在调用父类初始化方法前完成初始化,所以直接报错。

  2. 第二个错误:Property 'self.paymentContext' not initialized at super.init call
    你后来修改代码时,可能把super.init(coder:)放在了属性赋值之前,对于let类型的config来说,这违反了Swift的初始化规则:父类初始化必须在所有子类存储属性初始化之后调用。

正确的初始化实现方案

我们需要同时兼容手动实例化(init())和Storyboard实例化(init?(coder:)),并且把重复的配置逻辑抽离出来,避免代码冗余:

import UIKit
import Stripe

class CheckoutViewController: UIViewController, STPPaymentContextDelegate {
    // 把paymentContext改为var,方便后续更新支付信息
    var paymentContext: STPPaymentContext?
    // let类型的config必须在super.init前初始化
    let config: STPPaymentConfiguration
    let customerContext = STPCustomerContext(keyProvider: MyAPIClient())
    
    // 手动实例化的初始化方法
    init() {
        self.config = STPPaymentConfiguration()
        super.init(nibName: nil, bundle: nil)
        setupPaymentContext()
    }
    
    // Storyboard实例化的初始化方法(必须实现)
    required init?(coder aDecoder: NSCoder) {
        self.config = STPPaymentConfiguration()
        super.init(coder: aDecoder)
        setupPaymentContext()
    }
    
    // 抽离共同的支付上下文配置逻辑
    private func setupPaymentContext() {
        // 配置账单地址要求
        config.requiredBillingAddressFields = .name
        // 创建支付上下文
        let context = STPPaymentContext(customerContext: customerContext, configuration: config, theme: .defaultTheme)
        context.delegate = self
        context.hostViewController = self
        self.paymentContext = context
    }
    
    // MARK: - STPPaymentContextDelegate 实现(示例)
    func paymentContextDidChange(_ paymentContext: STPPaymentContext) {
        // 处理支付上下文变化
    }
    
    func paymentContext(_ paymentContext: STPPaymentContext, didFailToLoadWithError error: Error) {
        // 处理加载失败
    }
    
    func paymentContext(_ paymentContext: STPPaymentContext, didCreatePaymentResult paymentResult: STPPaymentResult, completion: @escaping STPPaymentStatusBlock) {
        // 处理支付结果
    }
}

如何通过Segue传递支付数据?

你的核心需求是传递支付金额等数据,只需在CheckoutViewController中添加对应的属性,然后在源ViewController的prepare(for:sender:)方法中赋值即可:

1. 在CheckoutViewController中添加支付信息属性

// 添加支付金额(Stripe使用最小货币单位,比如1000代表10美元)
var paymentAmount: Int = 0
// 支付货币代码,默认USD
var paymentCurrency: String = "USD"

2. 在源ViewController的Segue准备方法中传递数据

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    guard let checkoutVC = segue.destination as? CheckoutViewController else { return }
    
    // 传递支付金额和货币
    checkoutVC.paymentAmount = 1500 // 15美元
    checkoutVC.paymentCurrency = "USD"
    
    // 更新支付上下文的订单信息
    checkoutVC.paymentContext?.paymentAmount = checkoutVC.paymentAmount
    checkoutVC.paymentContext?.paymentCurrency = checkoutVC.paymentCurrency
}

你之前修改的代码为什么不可行?

你尝试的代码把super.init(coder:)放在了属性赋值的最后,但存在两个问题:

  1. 虽然局部变量赋值给self.config是在super.init之前,但直接在初始化方法中设置paymentContext?.delegate = self时,self还未完全初始化完成,可能引发潜在问题;
  2. 代码没有抽离重复逻辑,手动实例化和Storyboard实例化的配置代码冗余,后续维护成本高。

按照上面的方案实现,既可以解决初始化错误,又能顺利通过Segue传递支付数据,满足你的需求。

内容的提问来源于stack exchange,提问作者dsonawave

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 11:07:42