簡體   English   中英

使用帶有可編碼協議的CoreData的問題

[英]Issue using CoreData with Codable protocol

我創建了兩個NSManagedObject類之一Songs ,一個用於Categories的每首歌曲。 他們之間存在一對多的關系。 我要做的是,我從服務器上下載了一個json文件,並使用Decodable對其進行了解析並將數據保存在CoreData中。 一切都很順利,除非我嘗試將歌曲添加到特定類別類型時崩潰。

在不同上下文中非法嘗試在對象之間建立關系“類別”

我知道這次崩潰是什么,我知道我有兩個上下文,一個是類別類,另一個是歌曲類。 問題在於使用Decodable編寫CoreData的教程太少了。 因此,現在我正在考慮一種方法,也許可以創建這些類的父類並在其中init上下文,然后在類別和歌曲的子類中調用super.init() 但是我真的做不到。 或者,也許有一種更簡單的方法。 我將在這里共享我的類的代碼以及發生錯誤的代碼。

struct CategoryData: Decodable {
    let data: [CategoryManagedObject]
}

@objc(CategoryManagedObject)
class CategoryManagedObject: NSManagedObject, Decodable {

    // MARK: - Core Data Managed Object
    @NSManaged var id: Int
    @NSManaged var name: String
    @NSManaged var imgUrl: String
    @NSManaged var coverPhotoBit64: String
    @NSManaged var jsonUrl: String
    @NSManaged var version: Int
    @NSManaged var order: Int
    @NSManaged var songs: NSSet?

    //var coreDataStack: CoreDataManager!

    enum CodingKeys: String, CodingKey {
        case name, coverPhotoBit64, id, jsonUrl, version, order
        case imgUrl = "coverPhoto"
    }


    // MARK: - Decodable
    required convenience init(from decoder: Decoder) throws {
        //try super.init(from: decoder, type: "Categories")
        guard let codingUserInfoKeyManagedObjectContext = CodingUserInfoKey.context,
        let managedObjectContext = decoder.userInfo[codingUserInfoKeyManagedObjectContext] as? NSManagedObjectContext,
            let entity = NSEntityDescription.entity(forEntityName: "Categories", in: managedObjectContext) else {
                fatalError("FALIED TO DECODE CATEGORIES")
        }


        self.init(entity: entity, insertInto: managedObjectContext)

        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(Int.self, forKey: .id)
        name = try container.decode(String.self, forKey: .name)
        imgUrl = try container.decode(String.self, forKey: .imgUrl)
        coverPhotoBit64 = try container.decode(String.self, forKey: .coverPhotoBit64)
        version = try container.decode(Int.self, forKey: .version)
        jsonUrl = try container.decode(String.self, forKey: .jsonUrl)
        order = try container.decode(Int.self, forKey: .order)
//        if let sArray = songs.allObjects as? [Song] {
//            songs = try container.decode(sArray.self, forKey: .song)
//        }


    }

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

}


public extension CodingUserInfoKey {
    // Helper property to retrieve the context
    static let context = CodingUserInfoKey(rawValue: "managedObjectContext")
}

// MARK: Generated accessors for songs
extension CategoryManagedObject {

    @objc(addSongsObject:)
    @NSManaged public func addToSongs(_ value: Song)

    @objc(removeSongsObject:)
    @NSManaged public func removeFromSongs(_ value: Song)

    @objc(addSongs:)
    @NSManaged public func addToSongs(_ values: NSSet)

    @objc(removeSongs:)
    @NSManaged public func removeFromSongs(_ values: NSSet)

}



@objc(Song)
public class Song: NSManagedObject, Decodable {

    @NSManaged var id: Int
    @NSManaged var name: String
    @NSManaged var artist: String
    @NSManaged var code: String
    @NSManaged var category: CategoryManagedObject

    enum CodingKeys: String, CodingKey {
        case name, id, artist, code
    }

    // MARK: - Decodable
    required convenience public init(from decoder: Decoder) throws {

        guard let codingUserInfoKeyManagedObjectContext = CodingUserInfoKey.context,
            let managedObjectContext = decoder.userInfo[codingUserInfoKeyManagedObjectContext] as? NSManagedObjectContext,
            let entity = NSEntityDescription.entity(forEntityName: "Songs", in: managedObjectContext) else {
                fatalError("FALIED TO DECODE CATEGORIES")
        }


        self.init(entity: entity, insertInto: managedObjectContext)

        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(Int.self, forKey: .id)
        name = try container.decode(String.self, forKey: .name)
        artist = try container.decode(String.self, forKey: .artist)
        code = try container.decode(String.self, forKey: .code)


    }

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

由於兩個不同的上下文,因此發生崩潰是在這里。

 func saveJsonSongsInDB(filename fileName: String, category: CategoryManagedObject) {

        do {
            let data = try Data(contentsOf: URL(string: fileName)!)
            //let context = CoreDataManager.shared.persistentContainer.newBackgroundContext()
            let decoder = JSONDecoder()
            decoder.userInfo[CodingUserInfoKey.context!] = dbContext
            //decoder.userInfo[CodingUserInfoKey.deferInsertion] = true
            coreDataStack.deleteAllRecords("Songs")
            let songs = try decoder.decode([Song].self, from: data)
            let s = NSSet(array: songs)
           // category.managedObjectContext?.insert(<#T##object: NSManagedObject##NSManagedObject#>)
           // dbContext.insert(category)
            //print("SONGS: \(songs)")
            category.addToSongs(s)  //----> CRASH

            try dbContext.save()
        } catch let err {
            print("error:\(err)")
        }

    }

首先使用一個上下文,該上下文在JSONDEcoder中傳遞

  • CategoryManagedObject songs聲明為非可選本機類型

     @NSManaged var songs: Set<Song> 
  • songs解碼為Set (是,可以),並將每首歌曲的類別設置為self

     songs = try container.decode(Set<Song>.self, forKey: .song) songs.forEach{ $0.category = self } 

就這樣。 您不必在CategoryManagedObject設置逆關系

要插入數據,您必須解碼[CategoryManagedObject]

 let decoder = JSONDecoder()
 decoder.userInfo[CodingUserInfoKey.context!] = dbContext    
 coreDataStack.deleteAllRecords("Songs")
 _ = try decoder.decode([CategoryManagedObject].self, from: data)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM