I have implemented JSON parsing with swift Codable and storing it with Coredata . My Code works fine while storing the JSON and fetching entities which don't have "transformable" attribute. But fetch entity fails and crashes with below log in case where any of it attribute is transformable. I need to keep transformable attribute in case of Custom Objects. Have a look at below core data model classes and fetch request for my implementation. Console log:
-[Decodable.Address initWithCoder:]: unrecognized selector sent to
instance 0x600000464c40
2018-06-14 11:26:52.768499+0530 Decodable[7870:2988621] [error] error:
exception handling request: <NSSQLFetchRequestContext: 0x600000381fb0>
, -[Decodable.Address initWithCoder:]: unrecognized selector sent to
instance 0x600000464c40 with userInfo of (null)
CoreData: error: exception handling request:
<NSSQLFetchRequestContext: 0x600000381fb0> , -[Decodable.Address
initWithCoder:]: unrecognized selector sent to instance 0x600000464c40
with userInfo of (null)
2018-06-14 11:26:52.777634+0530 Decodable[7870:2988621] ***
Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '-[Decodable.Address
initWithCoder:]: unrecognized selector sent to instance
0x600000464c40'
ViewController.swift
let request = NSFetchRequest<Clinic>(entityName: "Clinic")
request.returnsObjectsAsFaults = true
do
{
managedObjectContext = appDelegate.persistentContainer.viewContext
let result = try managedObjectContext.fetch(request)//***Crashes!!
}
catch
{
print("no record found")
}
Clinic+CoreDataClass.swift
import Foundation
import CoreData
public class Clinic: NSManagedObject, NSCoding {
public func encode(with aCoder: NSCoder) {
aCoder.encode(address, forKey: ClinicCodingKeys.address.rawValue)
// also encode other class attributes
}
public required convenience init?(coder aDecoder: NSCoder) {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
guard let contextUserInfoKey = CodingUserInfoKey.context,
let managedObjectContext =
appDelegate.persistentContainer.viewContext as?
NSManagedObjectContext,
let entityDescription =
NSEntityDescription.entity(forEntityName:"Clinic", in:
managedObjectContext) else { fatalError() }
self.init(entity: entityDescription, insertInto:
appDelegate.persistentContainer.viewContext)
self.address = aDecoder.decodeObject(forKey:
ClinicCodingKeys.address.rawValue) as? Address
//*** Also decode other attributes
}
public override func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: ClinicCodingKeys.self)
try container.encode(remoteid , forKey: .remoteid)
try container.encode(landline ?? "" , forKey: .landline)
try container.encode(name ?? "", forKey: .name)
try container.encode(address , forKey: .address)
try container.encode(mobile ?? "", forKey: .mobile)
try container.encode(email ?? "", forKey: .email)
}
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:"Clinic", in:
managedObjectContext) else { fatalError() }
self.init(entity: entity, insertInto: managedObjectContext)
let values = try decoder.container(keyedBy: ClinicCodingKeys.self)
remoteid = try values.decode(Int16.self, forKey: .remoteid)
landline = try values.decode(String.self, forKey: .landline)
name = try values.decode(String.self, forKey: .name)
address = try values.decode(Address.self, forKey: .address)
mobile = try values.decode(String.self, forKey: .mobile)
email = try values.decode(String.self, forKey: .email)
}
}
Clinic+CoreDataProperties.swift
import Foundation
import CoreData
extension Clinic: Codable {
@nonobjc public class func fetchRequest() -> NSFetchRequest<Clinic> {
return NSFetchRequest<Clinic>(entityName: "Clinic")
}
@NSManaged public var remoteid: Int16
@NSManaged public var landline: String?
@NSManaged public var name: String?
@NSManaged public var address: Address?//***** Transformable attribute
//for core data model class Address
@NSManaged public var mobile: String?
@NSManaged public var email: String?
enum ClinicCodingKeys: String, CodingKey {
case remoteid = "_id"
case landline
case name
case address
case mobile
case email
}
}
Address+CoreDataClass.swift
import Foundation
import CoreData
public class Address: NSManagedObject {
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(address ?? "" , forKey: .address)
try container.encode(area ?? "" , forKey: .area)
try container.encode(postalcode ?? "" , forKey: .postalcode)
try container.encode(city ?? "" , forKey: .city)
try container.encode(state ?? "" , forKey: .state)
try container.encode(country ?? "" , forKey: .country)
try container.encode(lat ?? "" , forKey: .lat)
try container.encode(lng ?? "" , forKey: .lng)
}
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:"Address", in:
managedObjectContext) else { fatalError() }
self.init(entity: entity, insertInto: managedObjectContext)
let values = try decoder.container(keyedBy: CodingKeys.self)
address = try values.decode(String.self, forKey: .address)
area = try values.decode(String.self, forKey: .area)
postalcode = try values.decode(String.self, forKey: .postalcode)
city = try values.decode(String.self, forKey: .city)
state = try values.decode(String.self, forKey: .state)
country = try values.decode(String.self, forKey: .country)
lat = try values.decode(String.self, forKey: .lat)
lng = try values.decode(String.self, forKey: .lng)
}
}
Address+CoreDataProperties.swift
import Foundation
import CoreData
extension Address : Codable{
@nonobjc public class func fetchRequest() -> NSFetchRequest<Address> {
return NSFetchRequest<Address>(entityName: "Address")
}
@NSManaged public var address: String?
@NSManaged public var area: String?
@NSManaged public var postalcode: String?
@NSManaged public var city: String?
@NSManaged public var state: String?
@NSManaged public var country: String?
@NSManaged public var lat: String?
@NSManaged public var lng: String?
enum CodingKeys: String, CodingKey
{
case address
case area
case postalcode = "postal_code"
case city
case state
case country
case lat
case lng
}
}
I have tried implementing initWithCoder: in Clinic+CoreDataClass.swift but it gives error - Cannot invoke initWith(entity: insertInto:). And I need to implement initwith(entity: insertinto:)
You are fetching it wrongly NSFetchRequest<Clinic>(entityName: "Clinic")
and you are not checking entity records before saving into result variable.
let request = NSFetchRequest<Clinic>(entityName: "Clinic")
request.returnsObjectsAsFaults = true
do
{
managedObjectContext = appDelegate.persistentContainer.viewContext
let result = try managedObjectContext.fetch(request)//***Crashes!!
}
catch
{
print("no record found")
}
Replace your code with fetchData()
function and make sure Entity name is same.
func fetchData() {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
let context = appDelegate.persistentContainer.viewContext
let fetchRequest = NSFetchRequest<NSFetchRequestResult>(entityName: "Clinic")
do{
let records = try context.fetch(fetchRequest)
if let records = records as? [NSManagedObject]{
if !records.isEmpty{
var result:[NSManagedObject] = records
print("coreData result : \(records)")
}else{
print("No record in Clinic entity")
}
}
}catch{
print("Error")
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.