¿Cómo guardar y leer la matriz de matriz en NSUserdefaults en Swift?

81

Necesito crear una matriz para agregar objetos con este formato como un diccionario en Swift: ["clave1": "valor1", "clave2": "valor2"]

Cuando trato de guardarlo con NSUserDefaultstodo es correcto, pero cuando lo leo NSUserDefaultscon la clave, esto falla. ¿Qué tipo de datos necesita mi var obj?

let def = NSUserDefaults.standardUserDefaults()
var key = "keySave"
var element: AnyObject!

var array1: [AnyObject!] = []
array1.append(["key1": "val1", "key2": "val2"])
array1.append(["key1": "val1", "key2": "val2"])

//save
var savestring : [AnyObject!]
savestring = array1
var defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(savestring, forKey: key)
defaults.synchronize()

//read
var obj: [AnyObject!] = []
if(obj != nil){
    print("size: ")
    print(obj.count) //vary long value confused..
    element = obj[0]  //crash
    print(element.objectForKey("key1"))
}
usuario3745888
fuente
3
Parece que NSUserDefaults puede manejar String pero no Array y Dictionary, trabajando solo para los tipos NS * que describen los documentos. Entonces esto parece un error en Swift.
zaph
Para ir un poco más allá de lo que dice @Zaph, probé con [String] y no funciona, pero funciona con [NSString]. Comprueba mi respuesta.
HpTerm

Respuestas:

215

La pregunta dice "matriz de matriz", pero creo que la mayoría de las personas probablemente vienen aquí solo para saber cómo guardar una matriz en UserDefaults . Para esas personas, agregaré algunos ejemplos comunes.

Matriz de cadenas

Guardar matriz

let array = ["horse", "cow", "camel", "sheep", "goat"]

let defaults = UserDefaults.standard
defaults.set(array, forKey: "SavedStringArray")

Recuperar matriz

let defaults = UserDefaults.standard
let myarray = defaults.stringArray(forKey: "SavedStringArray") ?? [String]()

Int matriz

Guardar matriz

let array = [15, 33, 36, 723, 77, 4]

let defaults = UserDefaults.standard
defaults.set(array, forKey: "SavedIntArray")

Recuperar matriz

let defaults = UserDefaults.standard
let array = defaults.array(forKey: "SavedIntArray")  as? [Int] ?? [Int]()

Matriz bool

Guardar matriz

let array = [true, true, false, true, false]

let defaults = UserDefaults.standard
defaults.set(array, forKey: "SavedBoolArray")

Recuperar matriz

let defaults = UserDefaults.standard
let array = defaults.array(forKey: "SavedBoolArray")  as? [Bool] ?? [Bool]()

Matriz de fechas

Guardar matriz

let array = [Date(), Date(), Date(), Date()]

let defaults = UserDefaults.standard
defaults.set(array, forKey: "SavedDateArray")

Recuperar matriz

let defaults = UserDefaults.standard
let array = defaults.array(forKey: "SavedDateArray")  as? [Date] ?? [Date]()

Matriz de objetos

Los objetos personalizados (y en consecuencia las matrices de objetos) requieren un poco más de trabajo para guardar UserDefaults. Consulte los siguientes enlaces para saber cómo hacerlo.

Notas

  • El operador de fusión nula ( ??) le permite devolver la matriz guardada o una matriz vacía sin fallar. Significa que si el objeto devuelve nil, ??se utilizará en su lugar el valor que sigue al operador.
  • Como se puede ver, la configuración básica es la misma para Int, Booly Date. También lo probé con Double. Hasta donde yo sé, cualquier cosa que pueda guardar en una lista de propiedades funcionará así.
Suragch
fuente
16

Solo para agregar a lo que dice @Zaph en los comentarios.

Tengo el mismo problema que tú, como para saber, la matriz de Stringno se guarda. Aunque Apple puentea tipos como String y NSString, no pude guardar una matriz de [String]ninguno de [AnyObject].

Sin embargo, una serie de [NSString] trabajos para mí.

Entonces su código podría verse así:

var key = "keySave"

var array1: [NSString] = [NSString]()
array1.append("value 1")
array1.append("value 2")

//save
var defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(array1, forKey: key)
defaults.synchronize()

//read
if let testArray : AnyObject? = defaults.objectForKey(key) {
    var readArray : [NSString] = testArray! as [NSString]
}

Tenga en cuenta que creé una matriz de NSString y no un diccionario. No verifiqué si funciona con un diccionario, pero probablemente tendrás que definir las cosas [NSString : NSString]para que funcione.

EDITAR

Releyendo tu pregunta y tu título, estás hablando array of array. Creo que mientras te quedes con NSString, una matriz de matriz funcionará. Sin embargo, si cree que mi respuesta es irrelevante, hágamelo saber en los comentarios y la eliminaré.

HpTerm
fuente
11

Aquí hay un ejemplo de lectura y escritura de una lista de objetos de tipo SNStockque implementa NSCoding: tenemos un descriptor de acceso para toda la lista watchlist, y dos métodos para agregar y eliminar objetos, es decir, addStock(stock: SNStock)y removeStock(stock: SNStock).

import Foundation

class DWWatchlistController {

  private let kNSUserDefaultsWatchlistKey: String = "dw_watchlist_key"

  private let userDefaults: NSUserDefaults

  private(set) var watchlist:[SNStock] {

    get {
      if let watchlistData : AnyObject = userDefaults.objectForKey(kNSUserDefaultsWatchlistKey) {
        if let watchlist : AnyObject = NSKeyedUnarchiver.unarchiveObjectWithData(watchlistData as! NSData) {
          return watchlist as! [SNStock]
        }
      }
      return []
    }

    set(watchlist) {
      let watchlistData = NSKeyedArchiver.archivedDataWithRootObject(watchlist)
      userDefaults.setObject(watchlistData, forKey: kNSUserDefaultsWatchlistKey)
      userDefaults.synchronize()
    }
  }

  init() {
    userDefaults = NSUserDefaults.standardUserDefaults()
  }

  func addStock(stock: SNStock) {
    var watchlist = self.watchlist
    watchlist.append(stock)
    self.watchlist = watchlist
  }

  func removeStock(stock: SNStock) {
    var watchlist = self.watchlist
    if let index = find(watchlist, stock) {
      watchlist.removeAtIndex(index)
      self.watchlist = watchlist
    }
  }

}

Recuerde que su objeto debe implementarseNSCoding o, de lo contrario, la codificación no funcionará. Así es como se SNStockve:

import Foundation

class SNStock: NSObject, NSCoding
{
  let ticker: NSString
  let name: NSString

  init(ticker: NSString, name: NSString)
  {
    self.ticker = ticker
    self.name = name
  }

  //MARK: NSCoding

  required init(coder aDecoder: NSCoder) {
    self.ticker = aDecoder.decodeObjectForKey("ticker") as! NSString
    self.name = aDecoder.decodeObjectForKey("name") as! NSString
  }

  func encodeWithCoder(aCoder: NSCoder) {
    aCoder.encodeObject(ticker, forKey: "ticker")
    aCoder.encodeObject(name, forKey: "name")
  }

  //MARK: NSObjectProtocol

  override func isEqual(object: AnyObject?) -> Bool {
    if let object = object as? SNStock {
      return self.ticker == object.ticker &&
        self.name == object.name
    } else {
      return false
    }
  }

  override var hash: Int {
    return ticker.hashValue
  }
}

¡Espero que esto ayude!

Zorayr
fuente
3

Prueba esto.

Para obtener los datos de UserDefaults.

var defaults = NSUserDefaults.standardUserDefaults()
var dict : NSDictionary = ["key":"value"]
var array1: NSArray = dict.allValues // Create a dictionary and assign that to this array
defaults.setObject(array1, forkey : "MyKey")

var myarray : NSArray = defaults.objectForKey("MyKey") as NSArray
println(myarray)
Alvin Varghese
fuente
Agrego var dict: [AnyObject!] = [] Y var array1: NSArray = dict pero esto está vacío, ¿cómo puedo hacerlo correctamente?
user3745888
@AlvinVarghese De hecho, prueba el código. Hay un error tipográfico e incluso cuando se corrige, lo único que se guarda es una matriz con una entrada: "valor".
zaph
3

Swift 4.0

Tienda:

let arrayFruit = ["Apple","Banana","Orange","Grapes","Watermelon"]    

 //store in user default
 UserDefaults.standard.set(arrayFruit, forKey: "arrayFruit")

Ir a buscar:

if let arr = UserDefaults.standard.array(forKey: "arrayFruit") as? [String]{
        print(arr)
    }
Señor Javed Multani
fuente
1

Aquí está:

var array : [String] = ["One", "Two", "Three"]
let userDefault = UserDefaults.standard
// set
userDefault.set(array, forKey: "array")
// retrieve 
if let fetchArray = userDefault.array(forKey: "array") as? [String] {
    // code 
}
Andrei Levchenko
fuente
0

Si está trabajando con Swift 5+ , debe usar UserDefaults.standard.setValue(value, forKey: key)y para obtener los datos guardados, debe usar UserDefaults.standard.dictionary(forKey: key).

Wimukthi Rajapaksha
fuente