保存自定义对象数组

时间:2018-01-29 14:02:34

标签: ios arrays swift

我尝试使用名为Sheet的自定义对象保存和检索备注数据。 但是当它运行时我遇到了崩溃。这是正确的方法,还是有其他方法可以解决这个问题?

工作表类

class Sheet {
    var title = ""
    var content = ""
}

这是UITableViewController的类

class NotesListTableVC: UITableViewController {

    var notes = [Sheet]()

    override func viewDidLoad() {
        super.viewDidLoad()

        if let newNotes = UserDefaults.standard.object(forKey: "notes") as? [Sheet] {
            //set the instance variable to the newNotes variable
            notes = newNotes
        }
    }


    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // Return the number of rows in the section.
        return notes.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        var cell = tableView.dequeueReusableCell(withIdentifier: "notesCELL", for: indexPath)

        cell.textLabel!.text = notes[indexPath.row].title

        return cell
    }

    // Add new note or opening existing note
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "editNote" {
            var noteContentVC = segue.destination as! NoteContentVC
            var selectedIndexPath = tableView.indexPathForSelectedRow
            noteContentVC.note = notes[selectedIndexPath!.row]
        }
        else if segue.identifier == "newNote" {
            var newEntry = Sheet()
            notes.append(newEntry)
            var noteContentVC = segue.destination as! NoteContentVC
            noteContentVC.note = newEntry
        }
        saveNotesArray()
    }

    // Reload the table view
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)

        self.tableView.reloadData()
    }

    // Deleting notes
    override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
        notes.remove(at: indexPath.row)
        tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
    }

    // Save the notes
    func saveNotesArray() {
        // Save the newly updated array
        UserDefaults.standard.set(notes, forKey: "notes")
        UserDefaults.standard.synchronize()
    }

}

我应该在哪里调用saveNotesArray函数?

3 个答案:

答案 0 :(得分:4)

您正在尝试将一组自定义对象保存到UserDefaults。您的自定义对象不是property list对象您应该使用Codable来保存UserDefaults中的非属性列表对象。

Swift 4

自定义类

class Sheet: Codable {
  var title = ""
  var content = ""
}

<强> ViewController.swift

class ViewController: UIViewController {

    var notes = [Sheet]()

    override func viewDidLoad() {
        super.viewDidLoad()

        getSheets()
        addSheets()
        getSheets()
    }
    func getSheets()
    {
        if let storedObject: Data = UserDefaults.standard.data(forKey: "notes")
        {
            do
            {
                notes = try PropertyListDecoder().decode([Sheet].self, from: storedObject)
                for note in notes
                {
                    print(note.title)
                    print(note.content)
                }
            }
            catch
            {
                print(error.localizedDescription)
            }
        }
    }
    func addSheets()
    {
        let sheet1 = Sheet()
        sheet1.title = "title1"
        sheet1.content = "content1"

        let sheet2 = Sheet()
        sheet2.title = "title1"
        sheet2.content = "content1"

        notes = [sheet1,sheet2]
        do
        {
            UserDefaults.standard.set(try PropertyListEncoder().encode(notes), forKey: "notes")
            UserDefaults.standard.synchronize()
        }
        catch
        {
            print(error.localizedDescription)
        }
    }
}

答案 1 :(得分:3)

你回答你提出的问题。

应用程序崩溃日志。

   [User Defaults] Attempt to set a non-property-list object ( "Sheet.Sheet" )

官方Apple信息。

  

默认对象必须是属性列表 - 即(或   对于集合,实例的组合):NSData,NSString,   NSNumber,NSDate,NSArray或NSDictionary。

     

如果要存储任何其他类型的对象,通常应该这样做   将其存档以创建NSData的实例。有关详细信息,请参阅   首选项和设置编程指南。

可能的解决方案之一:

class Sheet : NSObject, NSCoding{
    var title:String?
    var content:String?

    func encode(with aCoder: NSCoder) {
        aCoder.encodeObject(self.title, forKey: "title")
        aCoder.encodeObject(self.content, forKey: "content")
    }

    required init?(coder aDecoder: NSCoder) {
        self.title = aDecoder.decodeObject(forKey: "title") as? String
        self.content = aDecoder.decodeObject(forKey: "content") as? String
    }
}

保存

userDefaults.setValue(NSKeyedArchiver.archivedDataWithRootObject(sheets), forKey: "sheets")

加载

sheets = NSKeyedUnarchiver.unarchiveObjectWithData(userDefaults.objectForKey("sheets") as! NSData) as! [Sheet]

答案 2 :(得分:0)

您发布的代码尝试将一组自定义对象保存到NSUserDefaults。你不能这样做。实现NSCoding方法没有帮助。您只能在UserDefaults中存储数组,字典,字符串,数据,数字和日期等内容。

您需要将对象转换为数据(就像您在某些代码中所拥有的那样)并将该数据存储在UserDefaults中。如果需要,您甚至可以存储数据数组。

当您回读数组时,您需要取消归档数据以取回Sheet对象。

将Sheet对象更改为:

class Sheet: NSObject, NSCoding {
    var title: String
    var content: String


    init(title: String, content: String) {
        self.title = title
        self.content = content
    }

    required convenience init(coder aDecoder: NSCoder) {
        let title = aDecoder.decodeObject(forKey: "title") as! String
        let content = aDecoder.decodeObject(forKey: "content") as! String
        self.init(title: title, content: content)
    }

    func encode(with aCoder: NSCoder) {
        aCoder.encode(title, forKey: "title")
        aCoder.encode(content, forKey: "content")
    }
}

进入类似的函数:

func loadData() {
    if let decoded  = userDefaults.object(forKey: "notes") as? Data, let notes = NSKeyedUnarchiver.unarchiveObject(with: decoded) as? [Sheet] {
         self.notes = notes
         self.tableView.reloadData()
    }

}

然后致电:

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    self.loadData()
}

saveNotesArray可以在添加新Notes后添加:

func saveNotesArray() {
    // Save the newly updated array
    var userDefaults = UserDefaults.standard
    let encodedData: Data = NSKeyedArchiver.archivedData(withRootObject: notes)
    userDefaults.set(encodedData, forKey: "notes")
    userDefaults.synchronize()
}