-2

I am trying to store an array in userDefaults but i am getting this error when i run my app:

'Attempt to insert non-property list object ( "Morning_Star_2.Event(title: Optional(\"test title\"), location: Optional(\"Test Location\"))" ) for key test'

Here is my code:

import UIKit

class ViewController: UIViewController {


    @IBOutlet weak var txtTitle: UITextField!

    @IBOutlet weak var txtLocation: UITextField!

    @IBOutlet weak var txtDate: UITextField!

    @IBOutlet weak var txtTime: UITextField!

    var eventsArray = [Event]()


       @IBAction func btnSave() {

        let savedEvents = UserDefaults.standard.object(forKey: "test")

        let event = Event(eventTitle: txtTitle.text!, eventLocation: txtLocation.text!)

        if let tempEvents = savedEvents {
            eventsArray = tempEvents as! [Event]
            eventsArray.append(event)

        }
        else {
            let event = Event(eventTitle: txtTitle.text!, eventLocation: txtLocation.text!)
            eventsArray.append(event)
        }

        UserDefaults.standard.set(eventsArray, forKey: "test")


        //print(eventsArray)

        }

}
Kunj Patel
  • 75
  • 3
  • 11
  • Your array has custom objects which can not be stored automatically in user defaults. Take a look here how to properly do that: https://stackoverflow.com/questions/2315948/how-to-store-custom-objects-in-nsuserdefaults – Eugene Dudnyk Mar 19 '17 at 20:03
  • 1
    Please [search on the error](http://stackoverflow.com/search?q=%5Bswift%5D+Attempt+to+insert+non-property+list+object) before posting. – rmaddy Mar 19 '17 at 20:05
  • you can not store object directly to UserDefaults so, it give this type of error. – Hardik Thakkar Mar 21 '17 at 07:25
  • Possible duplicate of [Attempt to set a non-property-list object as an NSUserDefaults](http://stackoverflow.com/questions/19720611/attempt-to-set-a-non-property-list-object-as-an-nsuserdefaults) – Hardik Thakkar Mar 21 '17 at 07:27

1 Answers1

0

To store custom objects in UserDefaults, your objects must

  1. Inherit from NSObject
  2. Conform to the NSCoding protocol

An example of the class implementation could look like this:

class Event: NSObject, NSCoding {

    private var eventTitle: String!
    private var eventLocation: String!

    init(eventTitle: String, eventLocation: String) {
        self.eventTitle = eventTitle
        self.eventLocation = eventLocation
    }

    override init() {

    }

    required convenience init?(coder aDecoder: NSCoder) {
        self.init()
        eventTitle = aDecoder.decodeObject(forKey: "eventTitle") as? String
        eventLocation = aDecoder.decodeObject(forKey: "eventLocation") as? String
    }

    func encode(with aCoder: NSCoder) {
        aCoder.encode(eventTitle, forKey: "eventTitle")
        aCoder.encode(eventLocation, forKey: "eventLocation")
    }

}

Now, you can only store certain objects in UserDefaults. Luckily the type Data can be stored in UserDefaults. You then need to convert your array to Data, and then store it.

let data = NSKeyedArchiver.archivedData(withRootObject: eventsArray) 
// This calls the encode function of your Event class

UserDefaults.standard.set(data, forKey: "test")
/* This saves the object to a buffer, but you will need to call synchronize, 
before it is actually saved to UserDefaults */

UserDefaults.standard.synchronize()

When you retrieve the data it comes back as Any?, which will have to be casted to your object:

if let data = UserDefaults.standard.object(forKey: "test") as? Data {
    if let storedData = NSKeyedUnarchiver.unarchiveObject(with: data) as? [Event] {
            // In here you can access your array
    }
}
Frederik
  • 384
  • 3
  • 7