将 NSManagedObject 数组与另一个“对象”类型 Swift 2 的数组进行比较

Posted

技术标签:

【中文标题】将 NSManagedObject 数组与另一个“对象”类型 Swift 2 的数组进行比较【英文标题】:Compare NSManagedObject Array with an Array of Another "Object" Type Swift 2 【发布时间】:2016-03-15 02:33:03 【问题描述】:

我正在寻找一种有效的方法来比较 NSManagedObject 数组和我从文件中读取的基本上相同的对象/结构的数组,即文件“Item”具有与 CoreData“Item”相同的属性.这是场景。我有一组从制表符分隔的文件中读取的项目。在游戏的第一个版本中,我会将这些物品存储到一个名为“物品”的核心数据实体中。

CoreData entity relationship

然后在游戏的第 2 版中,我可能会在平面文件中添加新项目或更新平面文件中的现有项目。我将在 CoreData 和文件数据之间使用的键是 itemId。当我发布游戏的第 2 版时,我将第 1 版 NSManagedObject 项目数据提取到一个数组中。我需要将 NSManagedObject 数组与版本 2 文件项数据进行比较。我可以遍历文件数据并为每个数组中的位置保留一个计数器,根据 itemId 匹配或不匹配根据需要递增它们。如果匹配,我想使用 == 来比较数据,因为所有属性都相同,但对象不同。我不想将文件数据对象存储为临时或虚拟 NSManagedObject。如果我这样做了,那么如果项目已经存在或项目需要更新,我就需要删除这个临时对象。

我只处理 100 多个项目,所以从性能的角度来看,这可能并不重要。出于比较目的创建 NSManagedObjects 并删除它们似乎效率低下,相反将 NSManagedObject 转换为“文件项”对象或结构也似乎效率低下。

那么,问题的简短版本是,如何使用 Swift 2 有效地将 NSManagedObject 数组与另一个“Object”类型的数组进行比较?

【问题讨论】:

【参考方案1】:

在做了一些额外的研究之后。我找到了以下链接: How to implement the new Core Data model builder 'unique' property in ios 9.0 Beta

1) 我在 managedObjectContext 定义中添加了一个 mergePolicy,在注释后的第 4 行:

lazy var managedObjectContext: NSManagedObjectContext = 
    // Returns the managed object context for the application (which is already bound to the persistent store coordinator for the application.) This property is optional since there are legitimate error conditions that could cause the creation of the context to fail.
    let coordinator = self.persistentStoreCoordinator
    var managedObjectContext = NSManagedObjectContext(concurrencyType: .MainQueueConcurrencyType)
    managedObjectContext.persistentStoreCoordinator = coordinator
    managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
    return managedObjectContext
()

2) 以及在插入对象后立即保存 managedObjectContext,我可以合并数据集。

    if let contentLineArray = arrayFromContentsOfFileWithName("Item") 
        // Loop through each item in the item file.  Add each item and save.  
        // Using managedObjectContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy
        for lineArray in contentLineArray 
            // skip the header line
            if lineArray == contentLineArray[0] 
                continue
            

            // get the individual attributes from the line
            let lineAttributeArray = lineArray.componentsSeparatedByString("\t")

            let itemEntity =  NSEntityDescription.entityForName(kItem as String, inManagedObjectContext:managedObjectContext)
            let fileItem = NSManagedObject(entity: itemEntity!, insertIntoManagedObjectContext: managedObjectContext) as! Item

            // set the properties of the managed object from the file object
            fileItem.itemId = Int(lineAttributeArray[0]) // unique key
            fileItem.slot = lineAttributeArray[1]
            fileItem.itemType = lineAttributeArray[2]
            fileItem.itemName = lineAttributeArray[3]
            fileItem.imageName = lineAttributeArray[4]
            fileItem.level = Int(lineAttributeArray[5])!
            fileItem.rarity = lineAttributeArray[6]
            fileItem.strength = Int(lineAttributeArray[7])!
        

        // conflicts are managed at the time of save
        saveManagedContext()

        // used for unit testing and validating
//            let nameSpaceClassName = NSStringFromClass(Item)
//            let className = nameSpaceClassName.componentsSeparatedByString(".").last! as String
//            let sortItemId = NSSortDescriptor(key: "itemId", ascending: true, selector: "localizedStandardCompare:")
//            let itemArray = CoreDataHelper.fetchEntities(className, managedObjectContext: managedObjectContext, predicate: nil, sortDescriptors: [sortItemId]) as! [Item]
//            print(itemArray)

    

func saveManagedContext() 
    if self.managedObjectContext.hasChanges 
        do 
            try self.managedObjectContext.save()
         catch 
            // Replace this implementation with code to handle the error appropriately.
            // abort() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
            let nserror = error as NSError
            NSLog("Unresolved error \(nserror), \(nserror.userInfo)")
            abort()
        

        #if DEBUG
            print("Managed context saved")
        #endif
    

本质上,如果我将“itemId”作为唯一键或“约束”添加到我的 Item CoreData 实体,CoreData 允许我执行 UPSERT。如果键存在则UP记录记录,如果键不存在则SERT记录。此链接还显示了如何为 CoreData 实体设置唯一约束。

Core Data Framework Reference -> NSMergePolicy Class Reference

【讨论】:

以上是关于将 NSManagedObject 数组与另一个“对象”类型 Swift 2 的数组进行比较的主要内容,如果未能解决你的问题,请参考以下文章

将一个 NSManagedObject 用于 UITableView 部分,它与另一个 NSManagedObject 的关系用于行?

如何在单个托管对象上下文中初始化新的 NSManagedObject 并设置与另一个 NSManagedObject 的关系?

如何在 CoreData 的代码中设置 NSManagedObject 与另一个 NSManagedObject 或它们的堆栈的关系?

核心数据谓词 - 检查数组中的任何元素是不是与另一个数组中的任何元素匹配

NSManagedObject 类关系中的 NSPredicate 键

如何在核心数据中保存与另一个对象相关的对象?