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

iOS开发:如何将IAPHelper中的商品价格传递至ViewController表格单元格?

嘿,这个需求其实很常见,咱们可以通过几种常用的iOS数据传递方式来实现,下面给你详细拆解:

方法一:闭包回调(推荐,低耦合)

这种方式最直观,直接在IAPHelper里定义一个闭包,当产品数据加载完成时触发,让ViewController拿到数据后刷新表格。

步骤1:修改IAPHelper,添加闭包属性

class IAPHelper: NSObject {
    var products: [SKProduct] = []
    // 定义闭包,用于传递加载完成的产品数据
    var onProductsLoaded: (([SKProduct]) -> Void)?
    
    // 发起产品请求的方法
    func fetchProducts(with productIdentifiers: Set<String>) {
        let request = SKProductsRequest(productIdentifiers: productIdentifiers)
        request.delegate = self
        request.start()
    }
}

extension IAPHelper: SKProductsRequestDelegate {
    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        self.products = response.products
        // 触发闭包,传递产品数据
        self.onProductsLoaded?(response.products)
        
        for product in response.products {
            print(product.price)
        }
    }
}

步骤2:在ViewController中接收数据并刷新表格

class ProductListViewController: UIViewController, UITableViewDataSource {
    @IBOutlet weak var tableView: UITableView!
    var products: [SKProduct] = []
    let iapHelper = IAPHelper()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.dataSource = self
        
        // 设置闭包,接收产品数据
        iapHelper.onProductsLoaded = { [weak self] products in
            guard let self = self else { return }
            self.products = products
            // 刷新表格
            self.tableView.reloadData()
        }
        
        // 发起产品请求(替换成你的产品ID集合)
        let productIDs: Set<String> = ["com.yourapp.product1", "com.yourapp.product2"]
        iapHelper.fetchProducts(with: productIDs)
    }
    
    // 表格数据源方法
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return products.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "ProductCell", for: indexPath)
        let product = products[indexPath.row]
        
        // 注意:SKProduct的price是NSDecimalNumber,需要结合priceLocale格式化显示
        let priceFormatter = NumberFormatter()
        priceFormatter.numberStyle = .currency
        priceFormatter.locale = product.priceLocale
        let formattedPrice = priceFormatter.string(from: product.price) ?? "\(product.price)"
        
        cell.textLabel?.text = formattedPrice
        // 你也可以设置产品名称等其他信息
        cell.detailTextLabel?.text = product.localizedTitle
        return cell
    }
}

方法二:Delegate代理模式

如果你的项目有多个地方需要监听IAP的状态,代理模式会更规范。

步骤1:定义代理协议

protocol IAPHelperDelegate: AnyObject {
    func iapHelper(_ helper: IAPHelper, didSuccessfullyLoadProducts products: [SKProduct])
}

class IAPHelper: NSObject {
    var products: [SKProduct] = []
    // 弱引用代理,避免循环引用
    weak var delegate: IAPHelperDelegate?
    
    // 发起请求方法同上...
}

extension IAPHelper: SKProductsRequestDelegate {
    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        self.products = response.products
        // 调用代理方法
        self.delegate?.iapHelper(self, didSuccessfullyLoadProducts: response.products)
    }
}

步骤2:ViewController实现代理

class ProductListViewController: UIViewController, UITableViewDataSource, IAPHelperDelegate {
    @IBOutlet weak var tableView: UITableView!
    var products: [SKProduct] = []
    let iapHelper = IAPHelper()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.dataSource = self
        // 设置代理
        iapHelper.delegate = self
        
        // 发起产品请求
        let productIDs: Set<String> = ["com.yourapp.product1", "com.yourapp.product2"]
        iapHelper.fetchProducts(with: productIDs)
    }
    
    // 实现代理方法
    func iapHelper(_ helper: IAPHelper, didSuccessfullyLoadProducts products: [SKProduct]) {
        self.products = products
        tableView.reloadData()
    }
    
    // 表格数据源方法同上...
}

方法三:NotificationCenter通知广播

如果你的App多个页面都需要接收产品数据,可以用通知的方式,但要记得在页面销毁时移除监听。

步骤1:IAPHelper发送通知

extension IAPHelper: SKProductsRequestDelegate {
    func productsRequest(_ request: SKProductsRequest, didReceive response: SKProductsResponse) {
        self.products = response.products
        // 发送通知,携带产品数据
        NotificationCenter.default.post(
            name: NSNotification.Name("IAPProductsLoaded"),
            object: response.products
        )
    }
}

步骤2:ViewController监听通知

class ProductListViewController: UIViewController, UITableViewDataSource {
    @IBOutlet weak var tableView: UITableView!
    var products: [SKProduct] = []
    let iapHelper = IAPHelper()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.dataSource = self
        
        // 添加通知监听
        NotificationCenter.default.addObserver(
            self,
            selector: #selector(handleProductsLoaded(_:)),
            name: NSNotification.Name("IAPProductsLoaded"),
            object: nil
        )
        
        // 发起产品请求
        let productIDs: Set<String> = ["com.yourapp.product1", "com.yourapp.product2"]
        iapHelper.fetchProducts(with: productIDs)
    }
    
    @objc private func handleProductsLoaded(_ notification: Notification) {
        if let loadedProducts = notification.object as? [SKProduct] {
            self.products = loadedProducts
            tableView.reloadData()
        }
    }
    
    // 页面销毁时移除监听,避免内存泄漏
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
    
    // 表格数据源方法同上...
}

关键注意点

  • 一定要用[weak self]避免循环引用,不管是闭包还是代理(代理要用weak修饰)。
  • SKProduct的price是NSDecimalNumber,直接显示会不友好,必须结合priceLocale用NumberFormatter格式化,这样会自动适配用户所在地区的货币符号和格式。
  • 确保表格的dataSource已经正确设置,单元格的复用ID和代码里的一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:03:05