1

I have an array of the custom object TemplateIndex, which I am trying to save and unsave to NSUserDefaults. But when I decode it, I get the following error:
Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value
Here is my custom object:

class TemplateIndex: NSObject, NSCoding {

var identifier: String
var sectionNumber: Int
var indexNumber: Int

init(identifier: String, sectionNumber: Int, indexNumber: Int) {
    self.identifier  = identifier
    self.sectionNumber = sectionNumber
    self.indexNumber  = indexNumber
}

required init?(coder aDecoder: NSCoder) {
    self.identifier = aDecoder.decodeObject(forKey: "identifier") as! String
    self.sectionNumber = aDecoder.decodeObject(forKey: "sectionNumber") as! Int
    self.indexNumber = aDecoder.decodeObject(forKey: "indexNumber") as! Int 
}

func encode(with aCoder: NSCoder) {
    aCoder.encode(self.identifier, forKey: "identifier")
    aCoder.encode(self.sectionNumber, forKey: "sectionNumber")
    aCoder.encode(self.indexNumber, forKey: "indexNumber")
}
}

var favouriteTemplateIdentifiersArray: [TemplateIndex] = []


And here are my save and unsave functions:

func unarchiveFaveTemplates() {

    guard let unarchivedObject = UserDefaults.standard.data(forKey: "faveTemplates") else {
        return
    }

    guard let unarchivedFaveTemplates = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(unarchivedObject) else {
        return
    }

    favouriteTemplateIdentifiersArray = unarchivedFaveTemplates as! [TemplateIndex]

    print("array opened")

}

func saveFaveTemplates() {

    do {

        let data = try NSKeyedArchiver.archivedData(withRootObject: favouriteTemplateIdentifiersArray, requiringSecureCoding: false)

        UserDefaults.standard.set(data, forKey: "faveTemplates")

        UserDefaults.standard.synchronize()

        print("array saved")

    } catch {
        fatalError("can't encode data.")
    }

}

Any help is appreciated, thankyou!

EDIT: Working Code

class TemplateIndex: Codable {

var identifier: String
var sectionNumber: Int
var indexNumber: Int

init(identifier: String, sectionNumber: Int, indexNumber: Int) {
    self.identifier  = identifier
    self.sectionNumber = sectionNumber
    self.indexNumber  = indexNumber
}

}

    func unarchiveFaveTemplates() {
    if let data = UserDefaults.standard.value(forKey: "faveTemplates") as? Data,
        let newArray = try? JSONDecoder().decode(Array<TemplateIndex>.self, from: data) {
        print("opened")
        favouriteTemplateIdentifiersArray = newArray
    }
}

 func saveFaveTemplates() {
        if let data = try? JSONEncoder().encode(favouriteTemplateIdentifiersArray) {
            UserDefaults.standard.set(data, forKey: "faveTemplates")
        }

        print("changes saved")
}   
brontea
  • 555
  • 4
  • 14
  • on the line; `self.sectionNumber = aDecoder.decodeObject(forKey: "sectionNumber") as! Int` – brontea Feb 13 '19 at 23:19
  • thanks for the advice, i will make it secure for sure. Still getting the error though :( – brontea Feb 13 '19 at 23:40
  • thanks, it seems to be working using the answer below but i'll come back to that if i get stuck with codeable :) – brontea Feb 13 '19 at 23:50

1 Answers1

-1

Forget about NSCoding and NSKeyedArchiver , you need to use Codable

struct TemplateIndex:Codable { 
    var identifier: String
    var sectionNumber,indexNumber: Int 
}

guard let data = UserDefaults.standard.data(forKey: "faveTemplates") else {
    return
}

do { 
   let arr = try JSONDecoder().decode([TemplateIndex].self,from:data)  
   let data = try JSONEncoder().encode(arr) 
   UserDefaults.standard.set(data, forKey: "faveTemplates")
 } catch {
   print(error)
}
Shehata Gamal
  • 98,760
  • 8
  • 65
  • 87
  • just an edit - i used the code from here to get it working https://stackoverflow.com/questions/44876420/save-struct-to-userdefaults – brontea Feb 14 '19 at 00:19
  • @brontea `PropertyListEncoder` is same as `JSONDecoder` the idea is conforming to `Codable` – Shehata Gamal Feb 14 '19 at 09:40