Основные данные -[Decodable.Address initWithCoder:]: нераспознанный селектор, отправленный экземпляру
Я реализовал разбор JSON с помощью swift Codable и сохранил его с помощью Coredata. Мой код работает нормально, сохраняя JSON и выбирая объекты, которые не имеют "трансформируемого" атрибута. Но извлечение сущности завершается сбоем и завершается с журналом ниже, если любой из его атрибутов можно преобразовать. Мне нужно сохранить трансформируемый атрибут в случае пользовательских объектов. Посмотрите ниже основные классы модели данных и получите запрос для моей реализации. Консольный журнал:
-[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")
}
Клиника +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)
}
}
Клиника +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
}
}
Адрес +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)
}
}
Адрес +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
}
}
Я попытался реализовать initWithCoder: в Clinic+CoreDataClass.swift, но это выдает ошибку - Невозможно вызвать initWith(entity: insertInto:). И мне нужно реализовать initwith(entity: insertinto:)
1 ответ
Вы забираете это неправильно NSFetchRequest<Clinic>(entityName: "Clinic")
и вы не проверяете записи сущностей перед сохранением в переменную результата.
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")
}
Замените свой код на fetchData()
и убедитесь, что имя объекта совпадает.
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")
}
}