I have the following data model in CoreData:
The relationships childs and parent are between objects of the same Type (Subject).
Subject+CoreDataClass.swift
import Foundation
import CoreData
@objc(Subject)
public class Subject: NSManagedObject {
}
Subject+CoreDataProperties
import Foundation
import CoreData
extension Subject {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Subject> {
return NSFetchRequest<Subject>(entityName: "Subject")
}
@NSManaged public var idauto: NSNumber?
@NSManaged public var longdescription: String?
@NSManaged public var parentid: NSNumber?
@NSManaged public var shortdescription: String?
@NSManaged public var title: String?
@NSManaged public var childs: NSSet?
@NSManaged public var parent: Subject?
}
I would like to return a Json file from the content of the sqlite database, so I make the Subject class conform to Codable protocol as follow:
Subject+CoreDataClass.swift
import Foundation
import CoreData
@objc(Subject)
public class Subject: NSManagedObject, Codable {
enum CodingKeys: String, CodingKey {
case title
case shortdescription
case longdescription
case parent
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(title ?? "", forKey: .title)
try container.encode(shortdescription ?? "", forKey: .shortdescription)
try container.encode(longdescription ?? "", forKey: .longdescription)
try container.encode(parent, forKey: .parent)
}
public required convenience init(from decoder: Decoder) throws {
guard let contextUserInfoKey = CodingUserInfoKey.context,
let managedObjectContext = decoder.userInfo[contextUserInfoKey] as? NSManagedObjectContext,
let entity = NSEntityDescription.entity(forEntityName: "Subject", in: managedObjectContext) else { fatalError("Failed to decode Subject!") }
self.init(entity: entity, insertInto: nil)
let values = try decoder.container(keyedBy: CodingKeys.self)
title = try values.decode(String.self, forKey: .title)
shortdescription = try values.decode(String.self, forKey: .shortdescription)
longdescription = try values.decode(String.self, forKey: .longdescription)
parent = try values.decode(Subject?.self, forKey: .parent)
}
}
extension CodingUserInfoKey {
static let context = CodingUserInfoKey(rawValue: "context")
}
I did not encode the relationship named childs because I get this error:
Fatal error: Optional<NSSet> does not conform to Encodable because NSSet does not conform to Encodable
To encode the data in an UIViewController I got this code:
import UIKit
import CoreData
class RootViewController: UIViewController {
var managedObjectContext: NSManagedObjectContext!
var subjects : [Subject] = []
func executeFetchRequest(completion:@escaping () -> ()){
let fetchRequest: NSFetchRequest<Subject> = Subject.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "TRUEPREDICATE")
let sortDescriptor = NSSortDescriptor(key: "idauto", ascending: true)
fetchRequest.sortDescriptors = [sortDescriptor]
fetchRequest.returnsObjectsAsFaults = false
managedObjectContext.perform {
self.subjects = try! fetchRequest.execute()
completion()
}
}
override func viewDidLoad() {
super.viewDidLoad()
executeFetchRequest(){ [weak self] in
guard let strongSelf = self else { return }
do{
let documentDirectoryURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
let jsonURL = URL(fileURLWithPath: "subjects", relativeTo: documentDirectoryURL.appendingPathComponent("Subjects")).appendingPathExtension("json")
let jsonEncoder = JSONEncoder()
jsonEncoder.outputFormatting = .prettyPrinted
let jsonData = try jsonEncoder.encode(strongSelf.subjects)
try jsonData.write(to: jsonURL)
} catch let error as NSError{
print("Error: \(error.description)")
}
}
}
}
The problem is that I get the following error in the function: public func encode(to encoder: Encoder) throws
Thread 1: EXC_BAD_ACCESS (code=2, address=0x16f4c3ea0)
If I don't encode the relationship paren,t I get the Json file ok.
How could I modify the code to also encode the relationship parent?