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

Swift:如何根据UserDefaults数据切换CollectionViewCell中的按钮?

解决从UserDefaults取数据控制CollectionViewCell按钮显示的问题

核心思路

不要在cell初始化阶段做按钮显示判断——此时cell的业务数据还未绑定,UserDefaults的判断会基于空数据导致逻辑失效。正确做法是:在cell的专属配置方法中,先读取UserDefaults数据,再结合当前业务数据决定按钮的显示状态、样式等。

具体实现步骤

1. 给CollectionViewCell添加配置方法

修改ItemsCollectionViewCell,新增统一配置方法,把数据赋值、按钮逻辑判断都整合到这里:

class ItemsCollectionViewCell: UICollectionViewCell {
    
    static let reuseId = "ItemsCollectionViewCell"
    var textItem: String = ""
    var categoryItem: String = ""
    var costItem: Int = 0
    var imageItem: String = ""
    
    let addCartButton: UIButton = {
        let button = UIButton(type: .system)
        button.backgroundColor = .gray
        button.titleLabel?.font = UIFont.boldSystemFont(ofSize: 12)
        button.setTitle("В корзину", for: .normal)
        button.setTitleColor(.white, for: .normal)
        button.translatesAutoresizingMaskIntoConstraints = false
        button.layer.cornerRadius = 12
        button.addTarget(self, action: #selector(tappedAddCart), for: .touchUpInside)
        return button
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupViews()
        // 初始化时默认隐藏按钮,等配置时再决定显示状态
        addCartButton.isHidden = true
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupViews() {
        // 添加按钮到视图并设置约束
        contentView.addSubview(addCartButton)
        NSLayoutConstraint.activate([
            addCartButton.bottomAnchor.constraint(equalTo: contentView.bottomAnchor, constant: -8),
            addCartButton.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 8),
            addCartButton.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -8),
            addCartButton.heightAnchor.constraint(equalToConstant: 32)
        ])
        // 其他视图的布局代码...
    }
    
    // 核心配置方法:接收商品数据,同步UI和UserDefaults逻辑
    func configure(with item: YourItemModel) {
        // 绑定业务数据
        textItem = item.title
        costItem = item.price
        imageItem = item.imageUrl
        categoryItem = "test"
        
        // 读取UserDefaults中已加入购物车的商品ID列表
        let defaults = UserDefaults.standard
        let cartItemIds = defaults.array(forKey: "cartItemIds") as? [String] ?? []
        
        // 根据UserDefaults数据判断按钮状态
        let isInCart = cartItemIds.contains(item.id) // 假设商品模型有唯一id属性
        addCartButton.isHidden = isInCart
        if !isInCart {
            addCartButton.setTitle("В корзину", for: .normal)
            addCartButton.backgroundColor = .gray
            addCartButton.isUserInteractionEnabled = true
        } else {
            // 已加入购物车时的按钮样式
            addCartButton.setTitle("已加入", for: .normal)
            addCartButton.backgroundColor = .green
            addCartButton.isUserInteractionEnabled = false
        }
        
        // 处理图片和标签赋值
        if let imageUrl = URL(string: item.imageUrl), let imageData = try? Data(contentsOf: imageUrl) {
            mainImageView.image = UIImage(data: imageData)
        } else {
            mainImageView.image = UIImage(systemName: "photo") // 占位图
        }
        nameLabel.text = item.title
        costLabel.text = "\(item.price) руб."
        nameLabel.textAlignment = .center
        costLabel.textAlignment = .center
    }
    
    @objc private func tappedAddCart() {
        // 点击按钮后,将商品ID存入UserDefaults
        let defaults = UserDefaults.standard
        var cartItemIds = defaults.array(forKey: "cartItemIds") as? [String] ?? []
        cartItemIds.append(textItem) // 建议替换为商品唯一ID
        defaults.set(cartItemIds, forKey: "cartItemIds")
        
        // 同步更新按钮状态
        addCartButton.isHidden = true
    }
}

2. 简化CollectionView的cell配置逻辑

在ItemsCollectionView的cellForItemAt方法中,直接调用cell的配置方法,无需零散赋值:

class ItemsCollectionView: UICollectionView, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    
    // 假设你的商品数据模型为YourItemModel
    var cells: [YourItemModel] = []
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = dequeueReusableCell(withReuseIdentifier: ItemsCollectionViewCell.reuseId, for: indexPath) as! ItemsCollectionViewCell
        // 直接传入当前商品数据完成配置
        cell.configure(with: cells[indexPath.row])
        return cell
    }
    
    // 其他代理方法...
}

关键注意事项

  • 避免初始化阶段处理业务逻辑:cell初始化时无绑定数据,此时读取UserDefaults做判断会得到错误结果。
  • 统一配置方法管理状态:所有UI状态、数据绑定都放到configure方法中,保证cell状态与数据同步,避免复用旧cell的错误状态。
  • UserDefaults读写规范:如果涉及多线程操作,可手动调用defaults.synchronize()(iOS 10+后系统自动同步,特殊场景需手动处理)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 08:55:37