如何使用UserDefaults.standard保存自定义数据?

时间:2018-06-18 07:45:39

标签: ios swift nsuserdefaults

我的数据类

import Foundation

class People {

let peopleImage : String
let peopleTime : Int
let peopleName : String

init(image:String, second:Int, name:String) {

    peopleImage = image
    peopleTime = second
    peopleName = name

}

我的数据列表文件

import Foundation

class CustomPeopleList {

    var peopleList = [

        People(image: "Man", second: 12, name: "Andy"),
        People(image: "Woman", second: 60, name: "Kevin"),



    ]

}

我的viewController:

let defaults = UserDefaults.standard    
var allPeopleList = CustomPeopleList

有一个按钮,当我点击按钮时它会删除数据列表中的第一个项目,但我发现它总是错误的。我的userdefault代码是这样的:

self.allPeopleList.remove(at: indexPathTimer.row)
let aaa = self.allPeopleList
let newPeopleData = NSKeyedArchiver.archivedData(withRootObject: self.allPeopleList)
self.defaults.set(aaa, forKey: "myPeopleData")

当我想使用它时

if let peopleData = defaults.data(forKey: "myPeopleData") as? [People] {
allPeopleList = peopleData
}
var allPeopleList = NSKeyedUnarchiver.unarchiveObject(with: peopleData!) as? [Peoples]

xcode说错了

3 个答案:

答案 0 :(得分:1)

我推荐Codable协议,并将数据保存为JSON。与Obj-C相关的NSKeyed(Un)Archiver

更快
  • 采用协议

    class People : Codable {
    
  • 将数组编码为JSON并保存

    do {        
       let newPeopleData = try JSONEncoder().encode(self.allPeopleList)
       self.defaults.set(newPeopleData, forKey: "myPeopleData")
    } catch { print(error)
    
  • 读取数据非常简单

    do {
       if let newPeopleData = self.defaults.data(forKey: "myPeopleData") {
          allPeopleList = try JSONDecoder().decode([People].self, from: newPeopleData)
       }
    } catch { print(error)
    

注意:我会以单数形式Person命名该课程,因为人物数组([People])具有重言性并且可以命名属性imagetimename

答案 1 :(得分:1)

如果您使用的是NSKeyedArchiverNSKeyedUnarchiver,那么您归档的对象必须是NSObject的子类并符合NSCoding

你必须做这样的事情:

class People: NSObject, NSCoding {

    let peopleImage : String
    let peopleTime : Int
    let peopleName : String

    init(image:String, second:Int, name:String) {
        peopleImage = image
        peopleTime = second
        peopleName = name
        super.init()
    }

    required init?(coder aDecoder: NSCoder) {
        self.peopleImage = aDecoder.decodeObject(forKey: "peopleImage") as! String
        self.peopleTime = aDecoder.decodeInteger(forKey: "peopleTime")
        self.peopleName = aDecoder.decodeObject(forKey: "peopleName") as! String
    }

    func encode(with aCoder: NSCoder) {
        aCoder.encode(self.peopleImage, forKey: "peopleImage")
        aCoder.encode(self.peopleTime, forKey: "peopleTime")
        aCoder.encode(self.peopleName, forKey: "peopleName")
    }
}

class CustomPeopleList: NSObject, NSCoding {

    var peopleList = [
        People(image: "Man", second: 12, name: "Andy"),
        People(image: "Woman", second: 60, name: "Kevin"),
    ]

    override init() {
        super.init()
    }

    required init?(coder aDecoder: NSCoder) {
        self.peopleList = aDecoder.decodeObject(forKey: "peopleList") as! [People]
    }

    func encode(with aCoder: NSCoder) {
        aCoder.encode(self.peopleList, forKey: "peopleList")
    }

}

var allPeopleList = CustomPeopleList()

let data = NSKeyedArchiver.archivedData(withRootObject: allPeopleList)

<强>然而

实施NSCoding可能非常详细。

如果您的对象包含基本实体,如整数,字符串和可编码实体的数组/字典,那么使用Swift的新Codable协议可能更容易。

这种方法的优点是,如果您的对象很简单,那么Swift可以为您生成编码和解码方法。

我个人推荐Codable。它可以比旧的NSCoding方法简单得多。

看起来像这样:

class People: Codable {

    let peopleImage : String
    let peopleTime : Int
    let peopleName : String

    init(image:String, second:Int, name:String) {
        peopleImage = image
        peopleTime = second
        peopleName = name
    }
}

class CustomPeopleList: Codable {

    var peopleList = [
        People(image: "Man", second: 12, name: "Andy"),
        People(image: "Woman", second: 60, name: "Kevin"),
    ]

}

var allPeopleList = CustomPeopleList()

// Can save in whatever format you want. JSON is always light and simple.
let data = try JSONEncoder().encode(allPeopleList)

// Decode the data object later.
let decodedPeopleList = try JSONDecoder().decode(CustomPeopleList.self, from: data)

答案 2 :(得分:0)

当您使用NSKeyedUnarchiverNSKeyedArchiver时,您需要从NSObject继承NSObject类。

要在userdefaaults中存储自定义对象,您需要继承自定义类窗体class People: NSObject { } ,否则会出现运行时错误/崩溃。

function replacement() {
  // For testing purposes, I created a spreadsheet that has data where 
  // your original code expects it.  I'm not sure if this is actually all 
  // in one spreadsheet or maybe spread across multiple, since you didn't
  // specify.
  var formularz = SpreadsheetApp.getActiveSpreadsheet();
  var total = formularz.getSheetByName('total');
  var wysylka = formularz.getSheetByName('wysylka');

  // CONFIGURATION

  // These are constants to capture the script configuration that can be
  // easily tweaked without diving into the code.

  // 0-based index of the first data sheet.
  var START_SHEET = 1;

  // 0-based index of the last data sheet.
  // NOTE: I only populated 3 data sheets in my test environment.
  var END_SHEET = 3;  

  // 0-based index of the row with sheet data within the total sheet.
  var TOTAL_STARTING_ROW = 16;

  // 0-based index of the column with sheet data within the total sheet.
  var TOTAL_COLUMN = 4;

  // 0-based index of the starting row within data sheets.
  var DATA_STARTING_ROW = 7;

  // 0-based index of the 'KOD' column within data sheets.
  var DATA_KOD_COLUMN = 2;

  // 0-based index of the 'il' column within data sheets.
  var DATA_IL_COLUMN = 7;

  // END OF CONFIGURATION

  // A prerequisite calculation based on the configuration.
  var numSheets = END_SHEET - START_SHEET + 1;

  // Use a single getValues() call to fetch all necessary total data.
  totalData = total.getRange(TOTAL_STARTING_ROW + 1, TOTAL_COLUMN + 1, numSheets).getValues();

  // Use an array to capture all of the rows we will append to the 'wysylka' sheet.
  var wysylkaRows = [];

  for (var i = 0; i < numSheets; i++) {  
    // Use a single getValues() call to fetch all necessary data from the data sheet.
    // Using getDataRange() to get all sheet data, instead of manually keeping track
    // of number of rows per sheet.
    var sheetData = formularz.getSheets()[START_SHEET + i].getDataRange().getValues();
    for (var j = DATA_STARTING_ROW; j < sheetData.length; j++) {
      if (totalData[i][0] > 1) {
        if (sheetData[j][DATA_IL_COLUMN] > 0) {
          // Push an array that represents a row we'll add to the 'wysylka' sheet.
          wysylkaRows.push([
            sheetData[j][DATA_KOD_COLUMN],
            sheetData[j][DATA_IL_COLUMN]
          ]);                  
        }
      }
    }
  }
  // Get a range for all of the accumulated rows.
  appendRange = wysylka.getRange(wysylka.getLastRow() + 1, 1,
                                 wysylkaRows.length, wysylkaRows[0].length);
  // Set all rows with a single setValues() call.
  appendRange.setValues(wysylkaRows);
}