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

如何在自定义TableViewCell添加收藏按钮并保存至UserDefaults实现收藏列表?

Got it, let's break this down into actionable steps to get your favorite button and filter working properly:

1. Update Your ErgWorkoutCell with a Favorite Button

First, add a favorite button to your custom cell (either via Storyboard/XIB or programmatically). Here's the updated cell code with button handling:

import UIKit

class ErgWorkoutCell: UITableViewCell {
    @IBOutlet weak var ergWorkoutTitle: UILabel!
    @IBOutlet weak var favoriteButton: UIButton!
    
    // Closure to pass tap events back to the view controller
    var favoriteTapped: ((_ isFavorite: Bool) -> Void)?
    
    // Track if the current workout is favorited
    private var isFavorited = false
    
    override func awakeFromNib() {
        super.awakeFromNib()
        setupFavoriteButton()
    }
    
    private func setupFavoriteButton() {
        // Set initial button image (adjust the image names to match your assets)
        favoriteButton.setImage(UIImage(systemName: "star"), for: .normal)
        favoriteButton.setImage(UIImage(systemName: "star.fill"), for: .selected)
    }
    
    // Call this from the VC to set the button state
    func configure(isFavorited: Bool) {
        self.isFavorited = isFavorited
        favoriteButton.isSelected = isFavorited
    }
    
    @IBAction func favoriteButtonTapped(_ sender: UIButton) {
        isFavorited.toggle()
        sender.isSelected = isFavorited
        favoriteTapped?(isFavorited)
    }
}

Don't forget to connect the favoriteButton outlet and its IBAction in your Storyboard/XIB!

2. Add a Helper for UserDefaults Favorite Storage

To keep your code clean, create a simple helper to manage saving/retrieving favorite workout IDs. First, make sure your workoutList model has a unique identifier (like id: String or id: Int — using titles can cause conflicts, so a unique ID is better):

// Create a helper struct to handle UserDefaults operations
struct FavoriteManager {
    private static let favoritesKey = "ErgWorkoutFavorites"
    
    static func getFavoriteWorkoutIDs() -> Set<String> {
        return Set(UserDefaults.standard.stringArray(forKey: favoritesKey) ?? [])
    }
    
    static func toggleFavorite(workoutID: String) {
        var favorites = getFavoriteWorkoutIDs()
        if favorites.contains(workoutID) {
            favorites.remove(workoutID)
        } else {
            favorites.insert(workoutID)
        }
        UserDefaults.standard.set(Array(favorites), forKey: favoritesKey)
    }
    
    static func isWorkoutFavorited(workoutID: String) -> Bool {
        return getFavoriteWorkoutIDs().contains(workoutID)
    }
}
3. Update the View Controller Logic

Now modify your view controller to handle the favorite button taps and filter for favorites:

First, Update cellForRowAt

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let selectedGroup = selectedWorkoutGroup(libraryFilter: libraryFilter, jsonErgWorkouts: jsonErgWorkouts, workoutGroupBox: workoutGroupBox)
    let cell = tableView.dequeueReusableCell(withIdentifier: "ergWorkoutCell") as! ErgWorkoutCell
    
    let workout = selectedGroup[indexPath.row]
    cell.ergWorkoutTitle.text = workout.title
    
    // Configure favorite button state
    let isFavorited = FavoriteManager.isWorkoutFavorited(workoutID: workout.id) // Replace `workout.id` with your actual unique identifier
    cell.configure(isFavorited: isFavorited)
    
    // Handle favorite button tap
    cell.favoriteTapped = { [weak self] isFavorited in
        FavoriteManager.toggleFavorite(workoutID: workout.id)
        // If we're on the Favorites tab, refresh the table to remove the workout if needed
        if self?.libraryFilter == 3 {
            tableView.reloadData()
        }
    }
    
    return cell
}

Then, Fix the selectedWorkoutGroup Method

Update the libraryFilter == 3 case to filter for favorited workouts:

func selectedWorkoutGroup(libraryFilter: Int, jsonErgWorkouts:[workoutList], workoutGroupBox: UITextField) -> [workoutList] {
    var selectedGroup = [workoutList]()
    let favoriteIDs = FavoriteManager.getFavoriteWorkoutIDs()
    
    switch libraryFilter {
    case 0:
        // Segmented Control #1 (Plan)
        selectedGroup = jsonErgWorkouts.filter { $0.group == workoutGroupBox.text }
    case 1:
        // Add your Tag filtering logic here
        selectedGroup = jsonErgWorkouts.filter { /* Your tag condition */ }
    case 2:
        // Add your Duration filtering logic here
        selectedGroup = jsonErgWorkouts.filter { /* Your duration condition */ }
    case 3:
        // Filter for favorited workouts
        selectedGroup = jsonErgWorkouts.filter { favoriteIDs.contains($0.id) } // Again, use your workout's unique ID
    default:
        selectedGroup = jsonErgWorkouts
    }
    return selectedGroup
}
4. Ensure Table Refreshes on Filter Switch

Make sure your segmented control's value changed event triggers a table reload. Add this action to your segmented control (connect it in Storyboard or add programmatically):

@IBAction func libraryFilterChanged(_ sender: UISegmentedControl) {
    libraryFilter = sender.selectedSegmentIndex
    tableView.reloadData()
}

Quick Notes:

  • Replace workout.id with the actual unique identifier from your workoutList model (if you don't have one, consider adding a uuid property to each workout in your JSON or model).
  • Adjust the favorite button images (the SF Symbols "star" and "star.fill" are used here, but you can use custom assets if needed).
  • UserDefaults is perfect for small datasets like favorites, but if you expect a large number of favorites, consider using Core Data instead.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:20:34