美文网首页
coreData问题再记录

coreData问题再记录

作者: revolution丶 | 来源:发表于2023-05-04 17:02 被阅读0次

    关键词: coreData关联关系无法回显, .relationshipKeyPathsForPrefetching, ***.xcdatamodeld - editor style

    背景:最近用swift重玩coreData,略有收获,怕日后忘记,故在此小计.另附demo一份,点击->传送门<-获取

    • 半路添加coreData
      如果新建项目要使用coreData,则新建时勾选即可.但要是老项目准备启用coreData呢,其实也不复杂,两步即可
    1. 新建一个coreData,如图
    2. 在AppDelegate中添加以下代码
        // MARK: - Core Data stack
        lazy var persistentContainer: NSPersistentContainer = {
            let container = NSPersistentContainer(name: "CoreDataTest")
            container.loadPersistentStores(completionHandler: { (storeDescription, error) in
                if let error = error as NSError? {
                    fatalError("Unresolved error \(error), \(error.userInfo)")
                }
            })
            return container
        }()
    
        // MARK: - Core Data Saving support
        func saveContext () {
            let context = persistentContainer.viewContext
            if context.hasChanges {
                do {
                    try context.save()
                } catch {
                    let nserror = error as NSError
                    fatalError("Unresolved error \(nserror), \(nserror.userInfo)")
                }
            }
        }
    

    效果如图


    此处要注意:需要将NSPersistentContainer(name: "CoreDataTest")的name换成上方新建的***.xcdatamodeld的名字.
    此处persistentContainer方法即操作coreData的容器方法,saveContext方法即为数据库存储方法,拿git来比喻的话就是,context(persistentContainer)方法存取数据是在暂存区活动(git add .) 而saveContext方法就是推远端(git remote)了.

    另外需要SceneDelegate的sceneDidEnterBackground方法添加代码

    func sceneDidEnterBackground(_ scene: UIScene) {
            // Called as the scene transitions from the foreground to the background.
            // Use this method to save data, release shared resources, and store enough scene-specific state information
            // to restore the scene back to its current state.
    
            // Save changes in the application's managed object context when the application transitions to the background.
            (UIApplication.shared.delegate as? AppDelegate)?.saveContext()
      }
    

    以确保程序在进入后台是保存数据.至此,半途添加coreData完毕.

    • coreData"替代"model
      coreData可以当做是model来用,
      其中,entities看做类,attributes看做属性.当按箭头选择了响应的Module和Codegen属性后会自动生成实体类的swift文件,只不过这个文件在左侧不显示,但这个类实际是可以像正常类一样被调用的
      let teacher = Teacher(context:context)
      teacher.id = 1
      teacher.subject = "科目1"
    
    另外,对于属性的设置,如图
    1. 如果未选中Optional,则这个属性必须进行赋值才能被coreData存储,否则save方法会报错,也无法存储.
    2. 属性的类型若是整型,如interger 16,则意味这个属性是16位整形数,也就是0到65535,如果对其赋值大于这个数,也是无法save的.
    • 关联关系
      对于关联关系,如图
    1. type属性设置一对多和一对一,如果设置了To Many(一对多)后,可以通过Count来对关联数量做限制,比如minimum=1,maximun=3,则1个teacher实体最多对应3个student,第4个student无法被关联.
    2. 关系的两端的Delete Rule的如果设为deny,则在删除两个有关联的实体时,会报错,这个设计是用来保护数据的,避免删除出错.对于没有影响的关系置为Nullify即可.
    3. 代码添加关联
    func allStudentsToTeacherWhosId1() {
            guard teacherArray.count != 0 else {
                return print("先生成老师数据")
            }
            let teacher = teacherArray[0]
            //M1:一对多
            for student in studentArray {
                if let teacherTeahStudentRelationship = teacher.teacherTeahStudents as? NSMutableOrderedSet {
                    teacherTeahStudentRelationship.add(student)
                    student.stuLearnFromTeacher = teacher
                } else {
                    teacher.teacherTeahStudents = NSMutableOrderedSet(object: student)
                }
            }
            //M2:一对一
            let book = WorkBook(context: context)
            book.name = "id1号老师的教案"
            teacher.teacherUseWorkBook = book
            saveData()
            sleep(1)
            getDataShow()
        }
    

    其中如果是一对多的关系,则只能能够用M1的方式处理,关系是个NSMutableOrderedSet(可变集合),所以只能用.add的方法添加.(笔者试过setValueForKey,array.append的方法,都无法添加,添加成功了也没法报存)
    一对一则用M2的方式处理,直接赋值即可.
    4.如果对两个实体a,b的关联关系设置为:a一对多b,b一对一a,则在代码中a添加b时,重复添加b无效,b只会属于最后一次添加的a实例.而如果a,b的关联关系设置为:a一对多b,b一对多a,则在代码中a添加b时,可以重复添加b,所有a实例的都b.

    • 读取储存的关联关系
    1. 可以通过以下语句在读取实体前预读关联关系(笔者实测,不用加也能读取,要是读取不出来,也可以试试)
    let request = Teacher.fetchRequest()
    request.relationshipKeyPathsForPrefetching = ["teacherTeahStudents"]
    
    1. 对于添加成功的关联关系,比如id=1老师对应x学生y学生z学生,
      储存后如果只是读出打印,则无法展示关联数据,如图 只是读出打印
      而如果是遍历该关系并打印,则可以正常展示.如图 遍历该关系并打印
      对于这种现象的原因笔者并不确定,搜索后结合推测可能是,coreData的节约内存优点导致的,即,如果并非真正使用则不完全加载关系,只有当真正使用关系时(比如遍历)才加载.这个只是个推测,仅供参考.
    • 最后,若有错误,恳请斧正。

    相关文章

      网友评论

          本文标题:coreData问题再记录

          本文链接:https://www.haomeiwen.com/subject/vnvxsdtx.html