首页 > 解决方案 > saveContext() 的工作差异取决于 viewController 的实例化。CoreData Enigma

问题描述

该项目有一个简约的 CoreData 堆栈。

我有一个 UIViewController 子类“AddOrChangeEntityVC”来创建 NSManagedObject,更改其属性并将数据写入 DB。

如果“AddOrChangeEntityViewController”是从 MyFirstVC、MySecondVC、...和 ​​MyNinthVC 创建的,则列出的函数可以正常工作,任何其他视图控制器都可以使用 BadVC。在这种情况下,尝试将实体写入数据库,所有属性 = nil。

我看到了这个错误。

Error Domain=NSCocoaErrorDomain Code=1560 "Multiple validation errors occurred."

对于每个必需的属性,例如

"Error Domain=NSCocoaErrorDomain Code=1570 \"firstProperty is a required value.\
UserInfo={NSValidationErrorObject=<APP.Entity: 0x600006917e80> (entity: Entity; id: 0x600000f152a0 <x-coredata:///Entity/t72AEC6D7-A854-40A3-BA9D-5830DFADC8AF2>; data: {\n    firstProperty = nil;\n    secondProperty = nil;\n}), NSValidationErrorKey = firstValue, NSLocalizedDescription=firstValue is a required value"
"Error Domain=NSCocoaErrorDomain Code=1570 \"secondProperty is a required value.\"

应该注意的是,在 saveContext() 调用之前,所有属性都经过验证。

AddOrChangeEntityVC: UIViewController {
var entity: Entity?

func saveEntity() -> Bool {
        //validating data

        if !validateData() {
            return false
        }
        //creating passenger
        if entity == nil {

            entity = Entity()
        }
        //saving entity
        if let entity = entity {


            //saving
            entity.firstProperty    = firstPropertyTextfield.text!
            entity.secondProperty   = secondPropertyTextfield.text!
            ...
        CoreDataStack.shared.saveContext()
        return true
    }
 }
Entity: NSManaged

class Entity: NSManagedObject {

    @nonobjc public class func fetchRequest() -> NSFetchRequest<Entity> {
        return NSFetchRequest<Entity>(entityName: "Entity")
    }

    @NSManaged public var firstProperty:        String
    @NSManaged public var secondProperty:       String

    convenience init() {
        let entity = NSEntityDescription.entity(forEntityName: "Entity",
         in: CoreDataStack.shared.persistentContainer.viewContext)!
        self.init(entity: entity, insertInto: CoreDataStack.shared.persistentContainer.viewContext)
            } 
}

核心数据管理器

    class CoreDataStack {

    static var shared = CoreDataStack() 
    lazy var persistentContainer: NSPersistentContainer = {
    let container = NSPersistentContainer(name: "APP")
    container.loadPersistentStores { storeDesription, error in
          guard error == nil else {
              fatalError("Unresolved error \(error!)")
          }
      }

      // Merge the changes from other contexts automatically. useв for Another Entity
    enter code here
      container.viewContext.automaticallyMergesChangesFromParent = true
      container.viewContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
      container.viewContext.shouldDeleteInaccessibleFaults = true
      return container
  }()

    func saveContext() {
        let context = persistentContainer.viewContext
        guard context.hasChanges else { return }
        do {
            try context.save()
        } catch let error as NSError{
            print("Error: \(error), \(error.userInfo)")
        }
    }    
}

从 anyVC 转换到 AddOrChangeEntityVC

        guard let entityVC = self.storyboard?.instantiateViewController(withIdentifier: "addEntityVC") as? AddOrChangeEntityVC else {return}
        self.navigationController?.pushViewController(entityVC, animated: true)
    ```

标签: swiftxcodecore-datansmanagedobjectnsmanagedobjectcontext

解决方案


好吧,Core Data 是神秘的,甚至是晦涩难懂的。

我做了这个简单的步骤。1)在 AddOrChangeEntityVC 我添加

var context: NSManagedObjectContext = CoreDataStack.shared.persistentContainer.newBackGroundContext()

2)在Entity的初始化中:NSManaged(如果我们需要创建它)

if entity == nil {
    entity = Entity(context: context)
    }

3) 出乎意料地面对,在 NSFetchingResultController 结果中添加了一些新的神秘实体后,所有属性 == nil 我在 tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 方法和 tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 通过从 fetchedResultsController.fetchedObjects 中删除?具有某些属性的元素 == nil。

func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
  return fetchedResultsController.fetchedObjects?.filter({!$0.firstProperty.isEmpty}).count ?? 0 
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
   if fetchedResultsController.object(at: indexPath).isValid {
        let entity = fetchedResultsController.object(at: indexPath)
        let cell = UITableViewCell()update(with: entity)
    ....
    }

推荐阅读