我创建一个联系人保存,然后创建一个位置并保存,然后将保存的位置分配给联系人.代码如下:
@IBAction func saveLocation(_ sender: AnyObject) { let processName = ProcessInfo.processInfo.globallyUniqueString let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext let location = Location(context: context) do { let fetchRequest: NSFetchRequest<Contact> = Contact.fetchRequest() fetchRequest.predicate = NSPredicate(format: "uniqueId == %@",contactIdentifierString) let fetchedResults = try context.fetch(fetchRequest) if let aContact = fetchedResults.first { // set location data location.uniqueId = processName location.locationName = locationNameTextField.text location.city = self.city location.state = self.state location.street = self.street location.zip = self.zip location.country = self.country // save data (UIApplication.shared.delegate as! AppDelegate).saveContext() location.contact = aContact myDelegate?.userSelectedContact(contactIdentifier: contactIdentifierString,locationIdentifier: processName) } } catch { print ("fetch task Failed",error) } // Check results do { let fetchRequest: NSFetchRequest<Location> = Location.fetchRequest() fetchRequest.predicate = NSPredicate(format: "uniqueId == %@",processName) let fetchedResults = try context.fetch(fetchRequest) if let aLocation = fetchedResults.first { print("+++++==========++++++++++") print("Location.Contact: \(aLocation.contact)") print("+++++==========++++++++++") } } catch { print ("location fetch Failed") } self.navigationController!.popViewController(animated: true) }
我只添加了一个位置,但是当我打印联系人实体时,我看到分配了两个位置,如下所示.
此外,位置实体之一具有正确的分配属性的值,其中另一个位置实体具有所有零值.
这搞砸了我的计划.当我在循环中查看位置实体属性以删除它们时,我现在看到三个位置实体
在我的代码的后半部分,当我尝试检索值时,它崩溃,因为两个额外的Location实体的所有属性都是nil.
我的问题:
因为我只添加了一个Location实体,所以应该只有一个Location实体,而且应该是唯一一个链接到Contact的实体.它显示了分配给Contact的两个Locations,然后当我得到计数时,我有三个Locations.看起来具有nil属性的Location实体会自行添加.我很迷惑.有人可以帮忙吗?
Location.Contact: Optional(<rg2nrg.Contact: 0x6000002c73f0> (entity: Contact; id: 0xd000000000240000 <x-coredata://7D46FA65-2590-409D-89E7-995F64F07483/Contact/p9> ; data: { email = vmail; firstName = vr; imageName = <89504e47 0d0a1a0a 0000000d 49484452 0000012c 0000012c 08@IBAction func saveLocation(_ sender: AnyObject) { let processName = ProcessInfo.processInfo.globallyUniqueString let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext let location = Location(context: context) do { let fetchRequest: NSFetchRequest<Contact> = Contact.fetchRequest() fetchRequest.predicate = NSPredicate(format: "uniqueId == %@",processName) let fetchedResults = try context.fetch(fetchRequest) if let aLocation = fetchedResults.first { print("+++++==========++++++++++") print("Location.Contact: \(aLocation.contact)") print("+++++==========++++++++++") } } catch { print ("location fetch Failed") } self.navigationController!.popViewController(animated: true) }0 00797d8e 75000000 01735247 4200aece 1ce90000 0009>;@IBAction func saveLocation(_ sender: AnyObject) { let processName = ProcessInfo.processInfo.globallyUniqueString let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext let location = Location(context: context) do { let fetchRequest: NSFetchRequest<Contact> = Contact.fetchRequest() fetchRequest.predicate = NSPredicate(format: "uniqueId == %@",processName) let fetchedResults = try context.fetch(fetchRequest) if let aLocation = fetchedResults.first { print("+++++==========++++++++++") print("Location.Contact: \(aLocation.contact)") print("+++++==========++++++++++") } } catch { print ("location fetch Failed") } self.navigationController!.popViewController(animated: true) }
lastName = r;
locations = (
"0xd000000001780002 <x-coredata://7D46FA65-2590-409D-89E7-995F64F07483/Location/p94>",
"0xd000000001740002 <x-coredata://7D46FA65-2590-409D-89E7-995F64F07483/Location/p93>"
);
phone = 22;
providerName = tara;
screenName = vr;
uniqueId = "7B17C228-50A6-4309-BD0D-CBCD8E8FAEA1-1106-00000128477D4DB1";
userType = Household;
}))
func deleteLocations() { var fetchedResults: [Location] = [] let contextLocation = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext do { fetchedResults = try contextLocation.fetch(Location.fetchRequest()) print("number of locations to be deleted:: \(fetchedResults.count) ") if fetchedResults.count > 0 { for location in fetchedResults{ print(location.locationName) contextLocation.delete(location) try contextLocation.save() print(location.locationName) } } } catch { print ("fetch contact Failed") } }
的init(背景:)
NSManagedObject上的此初始化程序不仅在调用Location(context:context)时在内存中创建一个空的Location对象,而且还将该对象插入到您传递的托管对象上下文中.一旦调用了saveContext(),该Location对象(如果没有进一步编辑它将为空)将被保留.
虽然init(context:)没有详细记录,但Apple似乎表明它与init(entity:insertInto:)的工作方式相同,只是该实体被自动计算出来.
保存位置(:)
在此函数中,您已创建了Location对象…
let location = Location(context: context)
…在检查联系人是否存在并设置属性之前.
if let aContact = fetchedResults.first
因此,如果发生提取失败或提取返回0结果,则在调用初始化程序时创建的空位置对象将保留在上下文中,以便在下次任何人调用saveContext()时保留.
解决方案和预防
在这种特殊情况下,您可能会发现在移动此行后您的问题将得到解决
let location = Location(context: context)
到下面的if let块:
if let aContact = fetchedResults.first { // create location here,not at beginning of method let location = Location(context: context) // set location data location.uniqueId = processName location.locationName = locationNameTextField.text location.city = self.city location.state = self.state location.street = self.street location.zip = self.zip location.country = self.country // save data (UIApplication.shared.delegate as! AppDelegate).saveContext() location.contact = aContact myDelegate?.userSelectedContact(contactIdentifier: contactIdentifierString,locationIdentifier: processName) }
作为在使用Core Data时可以防止此问题的一般规则,不要在任何NSManagedObject子类上使用init(context :),除非您首先执行了所有必要的检查并确定要立即将项插入上下文.