基于UserDefaults实现iOS表格视图的收藏功能
Hey there! Let’s tackle this UserDefaults persistence problem for your image favorites—no overkill Core Data required. I’ll break this down step by step so it makes total sense.
First, let’s get one key rule straight: never store actual UIImage objects in UserDefaults. It’s designed for lightweight, serializable data like strings, numbers, or arrays of those types. Instead, we’ll store unique identifiers for each image (like a server-provided ID, or the image’s URL as a string) — this keeps things fast and simple.
Step 1: Define a Reusable Key
Start by creating a constant for your UserDefaults key. This avoids typos and makes your code cleaner:
// Add this to a helper file or at the top of your view/controller private let favoritedImageIDsKey = "FavoritedImageIDs"
Step 2: Handle Favorite Button Taps (Home View)
When a user taps the favorite button, we’ll update a list of saved IDs in UserDefaults. Here’s how to do it in both SwiftUI and UIKit:
SwiftUI Example
Assume you have an ImageModel with a unique id property:
struct ImageCell: View { let image: ImageModel @State private var isFavorited: Bool = false private let userDefaults = UserDefaults.standard var body: some View { HStack { // Your image view here Image(uiImage: image.uiImage) .resizable() .frame(width: 80, height: 80) Spacer() Button(action: toggleFavorite) { Image(systemName: isFavorited ? "star.fill" : "star") .foregroundColor(isFavorited ? .yellow : .gray) } } .onAppear(perform: loadFavoriteStatus) } private func loadFavoriteStatus() { // Get existing favorite IDs, or an empty array if none exist let favoritedIDs = userDefaults.stringArray(forKey: favoritedImageIDsKey) ?? [] isFavorited = favoritedIDs.contains(image.id) } private func toggleFavorite() { // Get the current list of favorites var favoritedIDs = userDefaults.stringArray(forKey: favoritedImageIDsKey) ?? [] if isFavorited { // Remove the image from favorites favoritedIDs.removeAll { $0 == image.id } } else { // Add the image to favorites favoritedIDs.append(image.id) } // Save the updated list back to UserDefaults userDefaults.set(favoritedIDs, forKey: favoritedImageIDsKey) // Toggle the button state isFavorited.toggle() } }
UIKit Example
For a UITableViewCell with a favorite button:
class ImageTableViewCell: UITableViewCell { @IBOutlet weak var favoriteButton: UIButton! private let userDefaults = UserDefaults.standard private var currentImageID: String = "" func configure(with image: ImageModel) { currentImageID = image.id // Load existing favorite status let favoritedIDs = userDefaults.stringArray(forKey: favoritedImageIDsKey) ?? [] let isFavorited = favoritedIDs.contains(image.id) // Update button appearance favoriteButton.setImage( UIImage(systemName: isFavorited ? "star.fill" : "star"), for: .normal ) favoriteButton.tintColor = isFavorited ? .systemYellow : .systemGray } @IBAction func favoriteTapped(_ sender: UIButton) { var favoritedIDs = userDefaults.stringArray(forKey: favoritedImageIDsKey) ?? [] if favoritedIDs.contains(currentImageID) { favoritedIDs.removeAll { $0 == currentImageID } } else { favoritedIDs.append(currentImageID) } userDefaults.set(favoritedIDs, forKey: favoritedImageIDsKey) // Refresh button state configure(with: ImageModel(id: currentImageID, /* other properties */)) } }
Step 3: Load Favorites in Your Collection View
In your favorites tab, fetch the saved IDs and filter your full image list to show only favorited items:
SwiftUI Favorites View
struct FavoritesView: View { let allImages: [ImageModel] // Your full list of images @State private var favoritedImages: [ImageModel] = [] private let userDefaults = UserDefaults.standard var body: some View { List(favoritedImages) { image in ImageCell(image: image) } .onAppear(perform: loadFavorites) } private func loadFavorites() { let favoritedIDs = userDefaults.stringArray(forKey: favoritedImageIDsKey) ?? [] // Filter full list to only include favorited images favoritedImages = allImages.filter { favoritedIDs.contains($0.id) } } }
UIKit Favorites View Controller
class FavoritesViewController: UIViewController { @IBOutlet weak var tableView: UITableView! let allImages: [ImageModel] private var favoritedImages: [ImageModel] = [] private let userDefaults = UserDefaults.standard override func viewDidLoad() { super.viewDidLoad() loadFavorites() tableView.reloadData() } private func loadFavorites() { let favoritedIDs = userDefaults.stringArray(forKey: favoritedImageIDsKey) ?? [] favoritedImages = allImages.filter { favoritedIDs.contains($0.id) } } } // Implement UITableViewDataSource methods to display favoritedImages
Key Tips to Avoid Headaches
- Use unique IDs: Make sure each image has a unique identifier (like a server ID or hashed URL) so you don’t accidentally mix up favorites.
- Don’t store large data: UserDefaults isn’t for big files — stick to small identifiers only. If you need to save images locally, use the file system instead and store the file paths in UserDefaults.
- Test edge cases: What if the user has no favorites? The
?? []operator ensures you always get an empty array instead ofnil.
内容的提问来源于stack exchange,提问作者Cameron Wickes

