Swift 4中基于Array与TableViewCell的数据持久化问题求助
Hey Markus, let’s fix that data persistence problem for your iOS password manager app. I’ll walk you through two solid options—UserDefaults and CoreData—showing exactly how to hook them up with your existing array and TableView setup.
UserDefaults is quick to implement, but note: it stores data in plaintext by default—you’ll want to add encryption for passwords (like using Keychain) if you go this route. Here’s how to integrate it:
Define a reusable password structure
Create aCodablestruct to represent your username/password pairs—this lets us easily convert the array to/from data for storage:struct PasswordItem: Codable { let username: String let password: String }Update your array type
Replace your existing array with one that holdsPasswordIteminstances:var passwordItems: [PasswordItem] = []Add save/load methods
- Save your array to UserDefaults whenever data changes:
func savePasswords() { do { let encodedData = try JSONEncoder().encode(passwordItems) UserDefaults.standard.set(encodedData, forKey: "SavedPasswords") } catch { print("Oops, failed to save passwords: \(error.localizedDescription)") } } - Load data when your view loads (call this in
viewDidLoad()):func loadPasswords() { guard let savedData = UserDefaults.standard.data(forKey: "SavedPasswords") else { return } do { passwordItems = try JSONDecoder().decode([PasswordItem].self, from: savedData) tableView.reloadData() // Refresh your TableView right away } catch { print("Failed to load passwords: \(error.localizedDescription)") } }
- Save your array to UserDefaults whenever data changes:
Connect to your TableView
UpdatecellForRowAtto use your new array:override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "YourCellIdentifier", for: indexPath) let item = passwordItems[indexPath.row] cell.textLabel?.text = item.username cell.detailTextLabel?.text = String(repeating: "*", count: item.password.count) // Hide plaintext password! return cell }Trigger saves
CallsavePasswords()after adding/editing a password, or add it toapplicationWillTerminatein your AppDelegate to ensure data is saved when the app exits.
CoreData is better for larger datasets and gives you built-in support for sorting, filtering, and relationships. Here’s how to set it up:
Create a CoreData Entity
- Open your
.xcdatamodeldfile, add a new Entity namedPasswordEntity - Add two attributes:
username(String) andpassword(String)
- Open your
Access the CoreData Context
In your ViewController, get the shared context from your AppDelegate:let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContextUpdate your array
Use an array ofPasswordEntityobjects instead of your current array:var passwordItems: [PasswordEntity] = []Fetch data from CoreData
Add a method to load existing passwords (call this inviewDidLoad()):func fetchPasswords() { let fetchRequest: NSFetchRequest<PasswordEntity> = PasswordEntity.fetchRequest() do { passwordItems = try context.fetch(fetchRequest) tableView.reloadData() } catch { print("Failed to fetch passwords: \(error.localizedDescription)") } }Save new passwords
When adding a new username/password pair, create a new entity and save the context:func addNewPassword(username: String, password: String) { let newPassword = PasswordEntity(context: context) newPassword.username = username newPassword.password = password do { try context.save() fetchPasswords() // Refresh the array and TableView } catch { print("Failed to save password: \(error.localizedDescription)") } }Connect to TableView
Just like with UserDefaults, updatecellForRowAtto use your CoreData array:override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "YourCellIdentifier", for: indexPath) let item = passwordItems[indexPath.row] cell.textLabel?.text = item.username cell.detailTextLabel?.text = String(repeating: "*", count: item.password?.count ?? 0) return cell }Add delete functionality (optional)
If you want users to delete passwords, implement the TableView’s edit action:override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) { if editingStyle == .delete { let itemToDelete = passwordItems[indexPath.row] context.delete(itemToDelete) do { try context.save() fetchPasswords() } catch { print("Failed to delete password: \(error.localizedDescription)") } } }
Important Security Note
Neither UserDefaults nor CoreData encrypt data by default. For a password manager, you must encrypt the password fields before storing them. Apple’s Keychain Services API is the right tool for this—you can store encrypted passwords linked to your app, keeping them safe even if the device is compromised.
内容的提问来源于stack exchange,提问作者Markus Sten

