通过ObjectID获取Core Data记录返回nil,求代码改进方案
Let's break down the issues in your code and fix them step by step—your problem stems from two key mistakes in how you handle permanent IDs and how you attempt to resolve them later.
1. Critical Order Mistake in the Save Method
You're saving the context before obtaining the permanent ID, which defeats the purpose of calling obtainPermanentIDs. Once you save the context, the temporary ID might not get upgraded properly, and you're also checking the wrong condition for whether the save succeeded (you're returning isSaved as whether the ID is temporary, which is backwards).
Here's the corrected save method:
func save(completion: (Bool) -> Void) { guard validate() else { completion(false) return } do { // First get the permanent ID BEFORE saving the context try managedObjectContext.obtainPermanentIDs(for: [user]) // Now save the context with the permanent ID in place coreDataStack.saveContext(managedObjectContext) // Verify the ID is now permanent before storing it let hasPermanentID = !user.objectID.isTemporaryID if hasPermanentID { UserDefaults.standard.set(user.objectID.uriRepresentation().absoluteString, forKey: Constansts.shared.kCurrentUser) } completion(hasPermanentID) } catch let error as NSError { print("Could not obtain permanent ID or save user. \(error.localizedDescription)") completion(false) } }
2. Invalid Persistent Store Coordinator in Fetch Code
You're creating a brand new NSPersistentStoreCoordinator when trying to resolve the URI—but this new coordinator isn't connected to your actual persistent store file, so it can't map the URI to a valid ObjectID. Always use the coordinator already set up in your CoreDataStack.
Here's the corrected fetch code:
let coreDataStack = CoreDataStack(modelName: "MyDB") do { guard let currentUserURIString = UserDefaults.standard.string(forKey: Constansts.shared.kCurrentUser), let objectURL = URL(string: currentUserURIString), // Use the existing coordinator from your CoreDataStack let objectID = coreDataStack.storeContainer.persistentStoreCoordinator.managedObjectID(forURIRepresentation: objectURL) else { fatalError("Could not find the user to create a new plan for him.") } let user = try coreDataStack.mainContext.existingObject(with: objectID) as! Users let viewController = segue.destination as! ViewController viewController.viewModel = NewPlanViewModel(for: user, with: coreDataStack, and: coreDataStack.mainContext) } catch let error as NSError { print("Could not get current user. \(error.localizedDescription)") }
Bonus Best Practices
- Avoid force casting (
as! Users) unless you're 100% certain the ObjectID maps to aUsersobject. Useas? Usersand handle the nil case gracefully instead of crashing. - Double-check that your
CoreDataStackcorrectly initializes the persistent store coordinator and links it to your store file—if that setup is broken, even the corrected code won't work.
内容的提问来源于stack exchange,提问作者J. Doe

