Reputation: 181
I am trying to save an array of classes and here is my code so far:
The array:
var person1 = person(name: "Bob", age: 22)
var person2 = person(name: "John", age: 10)
var array = [person1, person2]
The custom class:
import UIKit
class person: NSObject, NSCoding {
var name : String
var age : Int
init(name: String, age: Int) {
self.name = name
self.age = age
}
required init (coder aDecoder: NSCoder) {
name = (aDecoder.decodeObject(forKey: "name") as? String)!
age = (aDecoder.decodeObject(forKey: "age") as? Int)!
}
func encode(with aCoder: NSCoder) {
aCoder.encode(name, forKey: "name")
aCoder.encode(age, forKey: "age")
}
}
To save the array:
let SavedData = NSKeyedArchiver.archivedData(withRootObject: array)
let defaults = UserDefaults.standard
defaults.set(SavedData, forKey: "myPeople")
To load the array:
let saveddata = UserDefaults.standard.object(forKey: "myPeople") as? Data
if saveddata != nil{
array = (NSKeyedUnarchiver.unarchiveObject(with: saveddata!) as? [person])!
}
The error is at the line age = (aDecoder.decodeObject(forKey: "age") as? Int)!
Unknown class iewripple in Interface Builder file.
Upvotes: 1
Views: 124
Reputation: 285039
The error occurs because you are encoding an Int
but decoding an object
which fails.
There is a dedicated method decodeInteger(forKey
.
Please conform to the naming convention that class names start with a capital letter and variable names start with a lowercase letter.
class Person: NSObject, NSCoding {
To solve the problem change the init(coder
method to
required init(coder aDecoder: NSCoder) {
name = aDecoder.decodeObject(forKey: "name") as! String
age = aDecoder.decodeInteger(forKey: "age")
}
Forced unwrapping the string is 100% safe since the value is always encoded as non-optional.
Save the array
let savedData = NSKeyedArchiver.archivedData(withRootObject: array)
UserDefaults.standard.set(savedData, forKey: "myPeople")
Load the array
if let savedData = UserDefaults.standard.object(forKey: "myPeople") as? Data {
array = NSKeyedUnarchiver.unarchiveObject(with: savedData) as! [Person]
}
Forced unwrapping is also safe in this case if the optional binding as? Data
succeeds.
Upvotes: 1
Reputation: 3499
You should not force unwrapping. Try getting
required init (coder aDecoder: NSCoder) {
name = (aDecoder.decodeObject(forKey: "name") as? String)!
age = (aDecoder.decodeObject(forKey: "age") as? Int)!
}
replaced by
required init (coder aDecoder: NSCoder) {
name = aDecoder.decodeObject(forKey: "name") as? String ?? ""
age = aDecoder.decodeInteger(forKey: "age")
}
Get
let saveddata = UserDefaults.standard.object(forKey: "myPeople") as? Data
if saveddata != nil{
array = (NSKeyedUnarchiver.unarchiveObject(with: saveddata!) as? [person])!
}
replaced by
if let data = UserDefaults.standard.object(forKey: "myPeople"),
let array = NSKeyedUnarchiver.unarchiveObject(with: data as! Data) as? [person] {
persons = array
}
I have tested. The code is working fine.
let person1 = person(name: "Bob", age: 22)
let person2 = person(name: "John", age: 10)
var persons = [person1, person2]
// Save data
let data = NSKeyedArchiver.archivedData(withRootObject: persons)
let defaults = UserDefaults.standard
defaults.set(data, forKey: "myPeople")
// Load data
if let data = UserDefaults.standard.object(forKey: "myPeople"),
let array = NSKeyedUnarchiver.unarchiveObject(with: data as! Data) as? [person] {
persons = array
}
Additionally, it is conventional to capitalise the first letter of a class name. You can check this out for naming convention.
Upvotes: 1