具有自定义类类型的 Swift CoreData 保存属性

Posted

技术标签:

【中文标题】具有自定义类类型的 Swift CoreData 保存属性【英文标题】:Swift CoreData Save Attribute with Type of Custom Class 【发布时间】:2019-09-26 06:59:23 【问题描述】:

我刚开始使用 CoreData 作为数据库来存储用户的数据,以支持离线应用程序的使用。我已经为我的对象设置了数据模型,并且某些属性必须存储在我的其他对象类的类型中。但是,它似乎已成功保存,但当我尝试从数据库中获取结果时它返回nil。我还查看了 SQLite 数据库文件,以查看存储到 CoreData 中的字段发生了什么事给我nil 作为结果(并且发现返回类型是Optional(Any)),发现数据的属性是存储在BLOB的类型中。

SQLite 中存储的结果:

最初,我的应用只能在网络可用的情况下使用,但我正在尝试将其转为支持离线访问。但是,我一直在坚持这些问题并且不知道如何解决它,甚至我不确定我是否以正确的方式进行。

我的自定义对象类的一个例子StudentMarkList

import Foundation
import UIKit
import CoreData

@objc(StudentMarkList)

class StudentMarkList: NSObject 
    var id = Int() // Student ID in DB (Primary Key)
    var paperId = String() // Paper ID which the student attended
    var studentClass = String() // Student class
    var totalMark = Int() // Total mark of the attended paper
    var allMarked = Bool() // Flag whether student's paper is all marked
    var markList = [MarkList]() // Array of marks for each question <- Custom object class of defining the structure of each question's mark

    override init() 
        super.init()
    

    init(id:Int, paperId:String, studentClass:String, totalMark:Int, allMarked:Bool, markList:[MarkList])
        self.id = id
        self.paperId = paperId
        self.studentClass = studentClass
        self.totalMark = totalMark
        self.allMarked = allMarked
        self.markList = markList
    

    func save() 
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else 
            return
        

        let managedContext = appDelegate.persistentContainer.viewContext
        managedContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy

        let entity = NSEntityDescription.entity(forEntityName: "StudentMarkList", in: managedContext)!
        let studentMarkList = NSManagedObject(entity: entity, insertInto: managedContext)

        studentMarkList.setValue(self.id, forKey: "id")
        studentMarkList.setValue(self.paperId, forKey: "paperId")
        studentMarkList.setValue(self.studentClass, forKey: "studentClass")
        studentMarkList.setValue(self.totalMark, forKey: "totalMark")
        studentMarkList.setValue(self.allMarked, forKey: "allMarked")
        studentMarkList.setValue(self.markList, forKey: "markList")

        if managedContext.hasChanges 
            do 
                try managedContext.save()
             catch let error as NSError 
                print("Could not save. \(error), \(error.userInfo)")
            
        
    

StudentMarkList的型号:

对应的自定义对象类MarkList

import Foundation
import UIKit
import CoreData

@objc(MarkList)

class MarkList: NSObject, NSCoding 
    func encode(with aCoder: NSCoder) 
        aCoder.encode(questionId, forKey: "questionId")
        aCoder.encode(questionNo, forKey: "questionNo")
        aCoder.encode(questionMark, forKey: "questionMark")
    

    required init?(coder aDecoder: NSCoder) 
        guard let questionId = aDecoder.decodeObject(forKey: "questionId") as? Int,
            let questionNo = aDecoder.decodeObject(forKey: "questionNo") as? Int,
            let questionMark = aDecoder.decodeObject(forKey: "questionMark") as? String else 
                return nil
        
        self.questionId = questionId
        self.questionNo = questionNo
        self.questionMark = questionMark
    

    var questionId = Int()
    var questionNo = Int()
    var questionMark = String()

    override init() 
        super.init()
    

    init(questionId: Int, questionNo: Int, questionMark: String) 
        self.questionId = questionId
        self.questionNo = questionNo
        self.questionMark = questionMark
    

    func save() 
        guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else 
            return
        

        let managedContext = appDelegate.persistentContainer.viewContext
        managedContext.mergePolicy = NSMergeByPropertyObjectTrumpMergePolicy

        let entity = NSEntityDescription.entity(forEntityName: "MarkList", in: managedContext)!
        let markList = NSManagedObject(entity: entity, insertInto: managedContext)

        markList.setValue(self.questionId, forKey: "questionId")
        markList.setValue(self.questionNo, forKey: "questionNo")
        markList.setValue(self.questionMark, forKey: "questionMark")

        if managedContext.hasChanges 
            do 
                try managedContext.save()
             catch let error as NSError 
                print("Could not save. \(error), \(error.userInfo)")
            
        
    

MarkList的型号:

函数save()用于将实例保存到CoreData作为对应的对象类。

希望有人可以帮助我或澄清我使用 CoreData 的概念。谢谢!

【问题讨论】:

Kelvin,您能否更新您的问题以确认MarkList 的数据类型(假设它是可转换的),如果可行,请提供模型编辑器StudentMarkList 的屏幕截图?跨度> @andrewbuilder 当然,我已经添加了实体的信息。 StudentMarkList 中提到的MarkList 的类型是Transformable。抱歉更新晚了... 【参考方案1】:

实现自定义类作为 CoreData 实体的属性。每个类都应被视为单独的实体,应通过关系管理数据链接

您必须为标记列表创建新实体,StudentMarkList 将是您的父实体。

只需将标记列表的关系添加到 studentMarkList,选择您的 StudentMarkList 实体并创建关系,如图所示。不要担心逆向下一步它会很清楚。

现在选择标记列表实体并添加如下所示的关系

请确保将类代码生成更改为使用手册

【讨论】:

请为关系使用更好的名称,通常的方法是将它们命名为与关系指向的实体相同,但以小写开头,如果是 to- 则以 s 结尾很多关系。所以markLists和studentMarkList @Abhi Yaduwanshi 感谢您的回答。我尝试添加关系,但似乎与 StudentMarkList 中的 MarkList 属性的数据仍然如前所示一样存储。 @Abhi Yaduwanshi 我试过了,当从 CoreData 获取结果时,它总是在 StudentMarkList 中为 markList 返回 nil... 在建立关系后,你必须为你的两个班级创建新的 NSObjectmanaged。让 arrMarksOrderedSet = NSOrderedSet(array: arrMarkList) StudentMarkList.addToMarks_rel(arrMarksOrderedSet) 在将数据保存到关系中的同时使用这种方法 @AbhiYaduwanshi 你的意思是创建子类和 NSObjectManaged 的​​核心数据属性吗?

以上是关于具有自定义类类型的 Swift CoreData 保存属性的主要内容,如果未能解决你的问题,请参考以下文章

Swift 和 CoreData 与自定义类作为可转换对象

Swift/IOS/CoreData:如何在自动生成的 CoreData 类中将 var 定义为枚举类型?

Swift:在 Core Data 中存储自定义类的数组

在 Swift 的 Core Data 中保存自定义类

Swift:CoreData NSManagedObject 的自定义设置器

如何在 swift 3 中将具有自定义类的数组转换为 JSON