[英]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.