coreData問題再記錄

關(guān)鍵詞: coreData關(guān)聯(lián)關(guān)系無法回顯, .relationshipKeyPathsForPrefetching, ***.xcdatamodeld - editor style

背景:最近用swift重玩coreData,略有收獲,怕日后忘記,故在此小計.另附demo一份,點擊->傳送門<-獲取

  • 半路添加coreData
    如果新建項目要使用coreData,則新建時勾選即可.但要是老項目準備啟用coreData呢,其實也不復(fù)雜,兩步即可
  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方法即為數(shù)據(jù)庫存儲方法,拿git來比喻的話就是,context(persistentContainer)方法存取數(shù)據(jù)是在暫存區(qū)活動(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()
  }

以確保程序在進入后臺是保存數(shù)據(jù).至此,半途添加coreData完畢.

  • coreData"替代"model
    coreData可以當(dāng)做是model來用,
    其中,entities看做類,attributes看做屬性.當(dāng)按箭頭選擇了響應(yīng)的Module和Codegen屬性后會自動生成實體類的swift文件,只不過這個文件在左側(cè)不顯示,但這個類實際是可以像正常類一樣被調(diào)用的
  let teacher = Teacher(context:context)
  teacher.id = 1
  teacher.subject = "科目1"

另外,對于屬性的設(shè)置,如圖
  1. 如果未選中Optional,則這個屬性必須進行賦值才能被coreData存儲,否則save方法會報錯,也無法存儲.
  2. 屬性的類型若是整型,如interger 16,則意味這個屬性是16位整形數(shù),也就是0到65535,如果對其賦值大于這個數(shù),也是無法save的.
  • 關(guān)聯(lián)關(guān)系
    對于關(guān)聯(lián)關(guān)系,如圖
  1. type屬性設(shè)置一對多和一對一,如果設(shè)置了To Many(一對多)后,可以通過Count來對關(guān)聯(lián)數(shù)量做限制,比如minimum=1,maximun=3,則1個teacher實體最多對應(yīng)3個student,第4個student無法被關(guān)聯(lián).
  2. 關(guān)系的兩端的Delete Rule的如果設(shè)為deny,則在刪除兩個有關(guān)聯(lián)的實體時,會報錯,這個設(shè)計是用來保護數(shù)據(jù)的,避免刪除出錯.對于沒有影響的關(guān)系置為Nullify即可.
  3. 代碼添加關(guān)聯(lián)
func allStudentsToTeacherWhosId1() {
        guard teacherArray.count != 0 else {
            return print("先生成老師數(shù)據(jù)")
        }
        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()
    }

其中如果是一對多的關(guān)系,則只能能夠用M1的方式處理,關(guān)系是個NSMutableOrderedSet(可變集合),所以只能用.add的方法添加.(筆者試過setValueForKey,array.append的方法,都無法添加,添加成功了也沒法報存)
一對一則用M2的方式處理,直接賦值即可.
4.如果對兩個實體a,b的關(guān)聯(lián)關(guān)系設(shè)置為:a一對多b,b一對一a,則在代碼中a添加b時,重復(fù)添加b無效,b只會屬于最后一次添加的a實例.而如果a,b的關(guān)聯(lián)關(guān)系設(shè)置為:a一對多b,b一對多a,則在代碼中a添加b時,可以重復(fù)添加b,所有a實例的都b.

  • 讀取儲存的關(guān)聯(lián)關(guān)系
  1. 可以通過以下語句在讀取實體前預(yù)讀關(guān)聯(lián)關(guān)系(筆者實測,不用加也能讀取,要是讀取不出來,也可以試試)
let request = Teacher.fetchRequest()
request.relationshipKeyPathsForPrefetching = ["teacherTeahStudents"]
  1. 對于添加成功的關(guān)聯(lián)關(guān)系,比如id=1老師對應(yīng)x學(xué)生y學(xué)生z學(xué)生,
    儲存后如果只是讀出打印,則無法展示關(guān)聯(lián)數(shù)據(jù),如圖
    只是讀出打印

    而如果是遍歷該關(guān)系并打印,則可以正常展示.如圖
    遍歷該關(guān)系并打印

    對于這種現(xiàn)象的原因筆者并不確定,搜索后結(jié)合推測可能是,coreData的節(jié)約內(nèi)存優(yōu)點導(dǎo)致的,即,如果并非真正使用則不完全加載關(guān)系,只有當(dāng)真正使用關(guān)系時(比如遍歷)才加載.這個只是個推測,僅供參考.
  • 最后,若有錯誤,懇請斧正。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容