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

跨多视图保存按钮图片状态的实现问题

解决角色拥有状态跨视图不保存的问题

这个问题我太熟了——本质就是状态没有被正确同步和持久化:你只在详情页的按钮点击时切换了图片,但状态没存在一个能被两个视图共享的地方,返回TableView后单元格重新加载,又回到了初始的空心圆状态。下面给你一套完整的解决方案:

1. 先创建一个角色数据模型(核心!)

首先要把角色的信息和拥有状态封装成一个模型类(用class而不是struct,保证引用传递,修改时两个视图操作的是同一个对象):

class Character {
    let name: String
    var isOwned: Bool // 标记是否已拥有
    
    init(name: String, isOwned: Bool = false) {
        self.name = name
        self.isOwned = isOwned
    }
}

2. 在TableView控制器中管理数据源

把原来的字符串数组换成这个模型数组,并且在单元格加载时根据模型的isOwned状态设置按钮(如果你的TableView单元格也显示拥有状态的话):

class CharactersTableVC: UITableViewController {
    // 用模型数组作为数据源
    var characters: [Character] = [
        Character(name: "哈利·波特"),
        Character(name: "赫敏·格兰杰"),
        Character(name: "罗恩·韦斯莱")
    ]
    
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(CharacterCell.self, forCellReuseIdentifier: "CharacterCell")
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return characters.count
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "CharacterCell", for: indexPath) as! CharacterCell
        let character = characters[indexPath.row]
        cell.nameLabel.text = character.name
        // 根据模型状态设置按钮图片
        cell.ownedButton.setImage(
            character.isOwned ? UIImage(named: "filledCircle") : UIImage(named: "emptyCircle"),
            for: .normal
        )
        return cell
    }
    
    // 跳转到详情页时传递模型对象
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        guard let detailVC = storyboard?.instantiateViewController(withIdentifier: "CharacterDetailVC") as? CharacterDetailVC else { return }
        detailVC.character = characters[indexPath.row]
        // 添加回调,让详情页通知TableView更新状态
        detailVC.onOwnershipChanged = { [weak self] in
            self?.tableView.reloadRows(at: [indexPath], with: .automatic)
        }
        navigationController?.pushViewController(detailVC, animated: true)
    }
}

3. 详情页处理按钮点击并同步状态

在详情页中接收模型对象,点击按钮时修改模型的isOwned状态,同时切换按钮图片,最后通过回调通知TableView刷新:

class CharacterDetailVC: UIViewController {
    var character: Character!
    var onOwnershipChanged: (() -> Void)? // 回调闭包
    
    @IBOutlet weak var nameLabel: UILabel!
    @IBOutlet weak var ownedButton: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        nameLabel.text = character.name
        // 初始化按钮状态
        updateOwnedButtonImage()
    }
    
    @IBAction func ownedButtonTapped(_ sender: UIButton) {
        // 切换拥有状态
        character.isOwned.toggle()
        // 更新按钮图片
        updateOwnedButtonImage()
        // 通知TableView刷新对应行
        onOwnershipChanged?()
    }
    
    private func updateOwnedButtonImage() {
        let imageName = character.isOwned ? "filledCircle" : "emptyCircle"
        ownedButton.setImage(UIImage(named: imageName), for: .normal)
    }
}

4. 可选:持久化状态(重启APP不丢失)

如果希望关闭APP后状态还能保留,可以用UserDefaults做简单持久化,给模型加扩展:

extension Character {
    // 保存单个角色状态到UserDefaults
    func save() {
        var savedCharacters = UserDefaults.standard.array(forKey: "SavedCharacters") as? [[String: Any]] ?? []
        // 查找已有角色并更新状态
        if let index = savedCharacters.firstIndex(where: { $0["name"] as? String == self.name }) {
            savedCharacters[index]["isOwned"] = self.isOwned
        } else {
            // 新角色添加进数组
            savedCharacters.append(["name": self.name, "isOwned": self.isOwned])
        }
        UserDefaults.standard.set(savedCharacters, forKey: "SavedCharacters")
    }
    
    // 从UserDefaults加载所有角色
    static func loadAll() -> [Character] {
        guard let savedData = UserDefaults.standard.array(forKey: "SavedCharacters") as? [[String: Any]] else {
            // 如果没有保存数据,返回默认角色列表
            return [
                Character(name: "哈利·波特"),
                Character(name: "赫敏·格兰杰"),
                Character(name: "罗恩·韦斯莱")
            ]
        }
        // 转换为Character模型数组
        return savedData.compactMap { data in
            guard let name = data["name"] as? String, let isOwned = data["isOwned"] as? Bool else { return nil }
            return Character(name: name, isOwned: isOwned)
        }
    }
}

然后在TableView控制器的viewDidLoad里加载数据:

override func viewDidLoad() {
    super.viewDidLoad()
    characters = Character.loadAll() // 加载保存的状态
    tableView.reloadData()
}

在详情页的按钮点击方法里添加保存:

@IBAction func ownedButtonTapped(_ sender: UIButton) {
    character.isOwned.toggle()
    updateOwnedButtonImage()
    character.save() // 保存状态到本地
    onOwnershipChanged?()
}

这样处理后,不管是返回TableView还是重启APP,角色的拥有状态都能正确保存和显示了!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 10:28:34