Core Data数据存储问题:无法保存/加载titles与bodys数组
Hey Matt, let's figure out why your Core Data save/load isn't working—there are a few key issues in your code that we can fix right away.
First, Let's Break Down the Problems
1. You're Not Persisting Changes to Disk
Your saveCoreData method deletes old data and creates a new entity, but you never call context.save()! All your changes only live in memory and disappear when the app closes. This is the biggest reason your data isn't sticking around.
2. Loading Logic Ignores Half Your Data
In loadCoreData, you use else if to pull title and body from each Saved entity:
if let title = result.value(forKey: "title") as? String { titles.append(title) } else if let body = result.value(forKey: "body") as? String { bodys.append(body) }
This means each entity only contributes either a title or a body to your arrays, not both. Since you want pairs of title/body, you need to fetch both properties from each entity.
3. You're Not Saving All Your Array Data
Your save code only creates one Saved entity, but you have entire titles and bodys arrays to store. You need to loop through both arrays and create an entity for each title-body pair.
4. Potential Thread Safety Risks
Core Data's viewContext is tied to the main thread. If loadAPIData runs in a background thread, directly accessing the context can cause crashes or data corruption.
Fixed Code Examples
Updated saveCoreData Method
func saveCoreData() { let appDelegate = UIApplication.shared.delegate as! AppDelegate let context = appDelegate.persistentContainer.viewContext // Delete existing data first let fetch = NSFetchRequest<NSFetchRequestResult>(entityName: "Saved") let deleteRequest = NSBatchDeleteRequest(fetchRequest: fetch) do { try context.execute(deleteRequest) context.reset() // Refresh context to reflect deletion } catch { print("Failed to delete old data: \(error)") return } // Make sure arrays are the same length to avoid mismatched pairs guard titles.count == bodys.count else { print("Titles and bodys arrays don't match in length!") return } // Save every title-body pair as a new Saved entity for index in 0..<titles.count { let savedEntity = NSEntityDescription.insertNewObject(forEntityName: "Saved", into: context) savedEntity.setValue(titles[index], forKey: "title") savedEntity.setValue(bodys[index], forKey: "body") } // Critical: Save changes to disk do { try context.save() print("Core Data saved successfully!") } catch { print("Failed to save Core Data: \(error)") } }
Updated loadCoreData Method
func loadCoreData() { // Clear existing array data first to avoid duplicates titles.removeAll() bodys.removeAll() let appDelegate = UIApplication.shared.delegate as! AppDelegate let context = appDelegate.persistentContainer.viewContext // Use a typed fetch request for better safety let request = NSFetchRequest<Saved>(entityName: "Saved") request.returnsObjectsAsFaults = false do { let results = try context.fetch(request) for result in results { // Fetch both title and body from each entity if let title = result.value(forKey: "title") as? String { titles.append(title) } if let body = result.value(forKey: "body") as? String { bodys.append(body) } } print("Loaded \(titles.count) items from Core Data") } catch { print("Failed to load Core Data: \(error)") } }
Bonus Tips
- Generate NSManagedObject Subclasses: Go to Xcode's
Editor > Create NSManagedObject Subclass...for yourSavedentity. This lets you use dot syntax likeresult.titleinstead ofvalue(forKey:), which is safer and easier to read. - Thread Safety: If
loadAPIDataruns in a background thread, wrap Core Data calls in the main thread:DispatchQueue.main.async { self.saveCoreData() // or self.loadCoreData() }
内容的提问来源于stack exchange,提问作者Matt Bart

