1

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.

2 Answers 2

1

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.

Sign up to request clarification or add additional context in comments.

Comments

1

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.

3 Comments

Thank you for answering however xcode doesn't allow me to not force unwrapping. It tells me to add as! Int after the age
My app now doesn't crash but puts the name and age of every person as "" and 0
Forced unwrapping is perfectly fine in this case. The class encodes always both non-optional properties so decoding the data can never be nil.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.