pkc
pkc

Reputation: 8516

How to add NSIndexPath to NSUserDefaults in swift

I am trying to save NSIndexPath at NSUserDefaults, but got the following exception:-

Attempt to set a non-property-list object {length = 2, path = 0 - 12} as an NSUserDefaults/CFPreferences value for key LastSelectedIndeX

My code:-

let selectedIndexPath = tableView.indexPathForSelectedRow
   NSUserDefaults.standardUserDefaults().setObject(selectedIndexPath, forKey: "lastSelectedIndex")
   NSUserDefaults.standardUserDefaults().synchronize()

So how can I save NSIndexPath so that I can use it later on at another view controller.

Upvotes: 5

Views: 2055

Answers (4)

vadian
vadian

Reputation: 285200

As mentioned by the others (NS)IndexPath is not property list compliant.

A solution is to use this simple extension of UserDefaults to save the IndexPath as an array of two integers

extension UserDefaults {

  func indexPath(forKey key : String) -> IndexPath?
  {
    guard let indexArray = array(forKey: key) as? [Int] else { return nil }
    return IndexPath(row: indexArray[0], section: indexArray[1])
  }

  func set(_ indexPath : IndexPath, forKey key: String)
  {
    set([indexPath.row, indexPath.section], forKey: key)
  }
}

You can find the syntax for an older Swift version in the edit history.

Upvotes: 3

Jeremy Buchman
Jeremy Buchman

Reputation: 11

This Swift code would work for any depth of IndexPath

extension UserDefaults {
    func indexPath(forKey key: String) -> IndexPath? {
        if let data = data(forKey: key), let indexPath = try? JSONDecoder().decode(IndexPath.self, from: data) {
            return indexPath
        }
        return nil
    }
    func set(_ indexPath: IndexPath, forKey key: String) {
        if let data = try? JSONEncoder().encode(indexPath) {
            set(data, forKey: key)
        }
    }
}

Upvotes: 1

Ketan Parmar
Ketan Parmar

Reputation: 27448

You can do something like this,

Save like,

  var myDefaults: NSUserDefaults = NSUserDefaults.standardUserDefaults()
    var indexPath: NSIndexPath = self.myTableView.indexPathForSelectedRow
    var data: NSData = NSKeyedArchiver.archivedDataWithRootObject(indexPath)
    myDefaults["lastSelectedIndex"] = myDefaults

Retrieve like,

    var data2: NSData = myDefaults.dataForKey("lastSelectedIndex")
    var indexPath2: NSIndexPath = NSKeyedUnarchiver.unarchiveObjectWithData(data2)

You have to convert indexpath to data then you can save and retrieve.

Hope this will help :)

Upvotes: 0

Kirit Modi
Kirit Modi

Reputation: 23407

You can't save directly indexPath in NSUserDefault. You can Store NSArray , NSDictionary , NSNumber , NSString and NSDictionary in NSUserDefault.

Store IndexPath using NSKeyedArchiver:

let data = NSKeyedArchiver.archivedDataWithRootObject(selectedIndexPath)
NSUserDefaults.standardUserDefaults().setObject(data, forKey: "indexKey")

Get IndexPath using NSKeyedArchiver:

let data1 = NSUserDefaults.standardUserDefaults().objectForKey("indexKey") as? NSData
let indexP1 = NSKeyedUnarchiver.unarchiveObjectWithData(data1!) as! NSIndexPath

Upvotes: 13

Related Questions