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
相关产品推荐
相关产品推荐

