【问题标题】:How to store array list of custom objects to NSUserDefaults?如何将自定义对象的数组列表存储到 NSUserDefaults?
【发布时间】:2020-01-14 07:59:13
【问题描述】:
class Item
{
    var name: String
    var collectionId: Int

    init(name: String, collectionId: Int) {
        self.name = name
        self.collectionId = collectionId

    }
}

class ViewController:UIViewController
{
    var itemList = [Item]()

    func recievedResults()
    {
        let defaults = NSUserDefaults.standardUserDefaults()
        defaults.setObject(self.itemList, forKey: "myList")
    }        
}

我收到一个错误“属性列表不能包含'CFType'类型的对象”

如何将 itemList 存储并获取到 NSUserDefaults?

【问题讨论】:

  • 在 Objective-c 中,NSUserdefaults 只接受原始数据: NSArray, NSString ,... 要在 NSUserdefaults 中保存自定义对象,您必须使用 NSKeyedArchiver(和 NSKeyedUnarchiver)将编码器和解码器方法添加到您的班级。我认为它在 Swift 中应用了相同的规则。
  • 您不应该在 NSUserDefaults 中存储 NSArray。请改用 plist。

标签: ios swift


【解决方案1】:

Swift 4 开始使用Codable 变得容易多了:

import Foundation

//Declaration
struct Item: Codable {
    var name: String
    var collectionId: Int
}

//Initialization
let itemA: Item = Item.init(name: "Bob A.", collectionId: 1)
let itemB: Item = Item.init(name: "Bob B.", collectionId: 1)
let items: [Item] = [itemA, itemB]

//Storing Items
if let encoded = try? JSONEncoder().encode(items) {
    UserDefaults.standard.set(encoded, forKey: "items")
}

//Retrieving Items
do {
    let storedObjItem = UserDefaults.standard.object(forKey: "items")
    let storedItems = try JSONDecoder().decode([Item].self, from: storedObjItem as! Data)
    print("Retrieved items: \(storedItems)")
} catch let err {
    print(err)
}

【讨论】:

    【解决方案2】:

    首先,您必须从 NSObject 继承 Item,使用编码器和解码器方法:

    class Item :NSObject
    {
        var name: String = ""
        var collectionId: Int = 0
    
        init(name: String, collectionId: Int) {
            self.name = name
            self.collectionId = collectionId
        }
    
        init(coder decoder: NSCoder) {
            self.name = decoder.decodeObjectForKey("name") as String
            self.collectionId = decoder.decodeIntegerForKey("collectionId")
        }
    
        func encodeWithCoder(coder: NSCoder) {
            coder.encodeObject(self.name, forKey: "name")
            coder.encodeInt(Int32(self.collectionId), forKey: "collectionId")
        }
    }
    

    然后,这些是从 NSUserDefaults 插入和检索的函数。

    func insertItems()
        {
            let defaults = NSUserDefaults.standardUserDefaults()
    
            let data = NSKeyedArchiver.archivedDataWithRootObject(itemList)
            NSUserDefaults.standardUserDefaults().setObject(data, forKey: "myList")
        }
    
    func retrieveItems()
    {
        let defaults = NSUserDefaults.standardUserDefaults()
    
        if let data = NSUserDefaults.standardUserDefaults().objectForKey("myList") as? NSData {
            let _mySavedList = NSKeyedUnarchiver.unarchiveObjectWithData(data) as [Item]
        }
    }
    

    例子:

    let item1 = Item(name: "Item 1", collectionId: 1)
    let item2 = Item(name: "Item 2", collectionId: 2)
    
    itemList.append(item1)
    itemList.append(item2)
    
    
    insertItems()
    retrieveItems()
    

    【讨论】:

      【解决方案3】:

      您需要为您的自定义类实现协议 NSCoding。请看这个Swift example

      【讨论】:

        【解决方案4】:

        正如this 堆栈溢出问题中所指出的,您不能在 NSUserDefaults 中存储自定义对象。

        但是您可以使您的类 NSCoding 兼容并存储来自 NSKeyedArchiver.archivedDataWithRootObject(...) 的 NSData:

        class Item : NSObject, NSCoding {
            var name: String
            var collectionId: Int
        
            init(name: String, collectionId: Int) {
                self.name = name
                self.collectionId = collectionId
            }
        
            required init(coder aDecoder: NSCoder) {
                collectionId = aDecoder.decodeIntegerForKey("collectionId")
                name = aDecoder.decodeObjectForKey("name") as String
            }
        
            func encodeWithCoder(aCoder: NSCoder) {
                aCoder.encodeObject(name, forKey: "name")
                aCoder.encodeInteger(collectionId, forKey: "collectionId")
            }
        }
        
        class ViewController: UIViewController {
        
            override func viewDidLoad() {
                super.viewDidLoad()
        
                recievedResults()
            }
        
            var itemList = [Item]()
        
            func recievedResults()
            {
                self.itemList.append(Item(name: "test", collectionId: 2))
        
                let defaults = NSUserDefaults.standardUserDefaults()
                defaults.setObject(NSKeyedArchiver.archivedDataWithRootObject(itemList), forKey: "myList")
        
                let data = defaults.objectForKey("myList") as NSData
                if let decodedList = NSKeyedUnarchiver.unarchiveObjectWithData(data) as? [Item]{
                    print("first item: \(decodedList)")
                }
            }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2011-01-19
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多