Reputation: 61
I was looking for a way to save Structs in the internal storage, until I found a form in the link: https://stackoverflow.com/a/40063878/6566615, I tried it with other Structs that I have and it works correctly, at least Is a possible quick exit to my problem of storing information inside Structs, now my new problem is that the following structure (CoursesG) has parameters, one of them being another Struct. I tried to do it in a fairly structured way based on the methodology described in the link, but I throw an error when trying to save the information.
struct CursosG {
let id: Int
let nrc: String
let profesor: String
let carreras: [Carreras]
let dia: String
let bloque: String
let sala: String
let idcurso: Int
let comentario: String
let curso: String
init(id: Int, nrc: String, profesor: String, carreras: [Carreras], dia: String, bloque: String, sala: String, idcurso: Int, comentario: String, curso: String) {
self.id = id
self.nrc = nrc
self.profesor = profesor
self.carreras = carreras
self.dia = dia
self.bloque = bloque
self.sala = sala
self.idcurso = idcurso
self.comentario = comentario
self.curso = curso
}
struct Carreras {
let id: Int
let nombre: String
let semestre: Int
init(id: Int, nombre: String, semestre: Int) {
self.id = id
self.nombre = nombre
self.semestre = semestre
}
}
}
extension CursosG {
init?(data: NSData) {
if let coding = NSKeyedUnarchiver.unarchiveObject(with: data as Data) as? Encoding {
id = coding.id as Int
nrc = coding.nrc as String
profesor = coding.profesor as String
carreras = coding.carreras as [Carreras]
dia = coding.dia as String
bloque = coding.bloque as String
sala = coding.sala as String
idcurso = coding.idcurso as Int
comentario = coding.comentario as String
curso = coding.curso as String
} else {
return nil
}
}
func encode() -> NSData {
return NSKeyedArchiver.archivedData(withRootObject: Encoding(self)) as NSData
}
private class Encoding: NSObject, NSCoding {
let id: NSInteger
let nrc: NSString
let profesor: NSString
let carreras: [Carreras]
let dia: NSString
let bloque: NSString
let sala: NSString
let idcurso: NSInteger
let comentario: NSString
let curso: NSString
init(_ CursosG: CursosG) {
id = CursosG.id as NSInteger
nrc = CursosG.nrc as NSString
profesor = CursosG.profesor as NSString
carreras = CursosG.carreras as [Carreras]
dia = CursosG.dia as NSString
bloque = CursosG.bloque as NSString
sala = CursosG.sala as NSString
idcurso = CursosG.idcurso as NSInteger
comentario = CursosG.comentario as NSString
curso = CursosG.curso as NSString
}
public required init?(coder aDecoder: NSCoder) {
if let id = aDecoder.decodeObject(forKey: "id") as? NSInteger { self.id = id } else { return nil }
if let nrc = aDecoder.decodeObject(forKey: "nrc") as? NSString { self.nrc = nrc } else { return nil }
if let profesor = aDecoder.decodeObject(forKey: "profesor") as? NSString { self.profesor = profesor } else { return nil }
if let carreras = aDecoder.decodeObject(forKey: "carreras") as? [Carreras] { self.carreras = carreras } else { return nil }
if let dia = aDecoder.decodeObject(forKey: "dia") as? NSString { self.dia = dia } else { return nil }
if let bloque = aDecoder.decodeObject(forKey: "bloque") as? NSString { self.bloque = bloque } else { return nil }
if let sala = aDecoder.decodeObject(forKey: "sala") as? NSString { self.sala = sala } else { return nil }
if let idcurso = aDecoder.decodeObject(forKey: "idcurso") as? NSInteger { self.idcurso = idcurso } else { return nil }
if let comentario = aDecoder.decodeObject(forKey: "comentario") as? NSString { self.comentario = comentario } else { return nil }
if let curso = aDecoder.decodeObject(forKey: "curso") as? NSString { self.curso = curso } else { return nil }
}
public func encode(with aCoder: NSCoder) {
aCoder.encode(id, forKey: "id")
aCoder.encode(nrc, forKey: "nrc")
aCoder.encode(profesor, forKey: "profesor")
aCoder.encode(carreras, forKey: "carreras")
aCoder.encode(dia, forKey: "dia")
aCoder.encode(bloque, forKey: "bloque")
aCoder.encode(sala, forKey: "sala")
aCoder.encode(idcurso, forKey: "idcurso")
aCoder.encode(comentario, forKey: "comentario")
aCoder.encode(curso, forKey: "curso")
}
}
}
extension CursosG.Carreras {
init?(data: NSData) {
if let coding = NSKeyedUnarchiver.unarchiveObject(with: data as Data) as? Encoding {
id = coding.id as Int
nombre = coding.nombre as String
semestre = coding.semestre as Int
} else {
return nil
}
}
func encode() -> NSData {
return NSKeyedArchiver.archivedData(withRootObject: Encoding(self)) as NSData
}
private class Encoding: NSObject, NSCoding {
let id: NSInteger
let nombre: NSString
let semestre: NSInteger
init(_ Carreras: CursosG.Carreras) {
id = Carreras.id as NSInteger
nombre = Carreras.nombre as NSString
semestre = Carreras.semestre as NSInteger
}
public required init?(coder aDecoder: NSCoder) {
if let id = aDecoder.decodeObject(forKey: "id") as? NSInteger { self.id = id } else { return nil }
if let nombre = aDecoder.decodeObject(forKey: "nombre") as? NSString { self.nombre = nombre } else { return nil }
if let semestre = aDecoder.decodeObject(forKey: "semestre") as? NSInteger { self.semestre = semestre } else { return nil }
}
public func encode(with aCoder: NSCoder) {
aCoder.encode(id, forKey: "id")
aCoder.encode(nombre, forKey: "nombre")
aCoder.encode(semestre, forKey: "semestre")
}
}
}
let encoded = CursosAllG.map { $0.encode()}
UserDefaults.standard.set(encoded, forKey: "my-key")
2017-02-11 15:53:27.404 Tongoy UCN[30475:714874] -[_SwiftValue encodeWithCoder:]: unrecognized selector sent to instance 0x600000486bd0
2017-02-11 15:53:27.491 Tongoy UCN[30475:714874] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_SwiftValue encodeWithCoder:]: unrecognized selector sent to instance 0x600000486bd0'
Upvotes: 0
Views: 454
Reputation: 116
NSUserDefaults is limited in the types it can handle: NSData, NSString, NSNumber, NSDate, NSArray, and NSDictionary. Thus no Swift objects or structs can be saved. Anything else must be converted to an NSData object.
NSUserDefaults does not work the same way as NSArchiver. Since you already have added NSCoder to your classes your best choice might be to save and restore with NSArchiver to a file in the Documents directory..
From the Apple NSUserDefaults Docs:
A default object must be a property list, that is, an instance of (or for collections a combination of instances of): NSData, NSString, NSNumber, NSDate, NSArray, or NSDictionary. If you want to store any other type of object, you should typically archive it to create an instance of NSData.
Upvotes: 1