首页 > 解决方案 > NSUserDefaultsController:“尝试将非属性列表对象...设置为键的 NSUserDefaults/CFPreferences 值...”

问题描述

我正在尝试NSUserDefaultsController在我的 Swift macOS 应用程序中实现首选项窗口。

我需要保留的设置之一是一组预设,由以下类定义:

class Preset: NSObject {
    var name = "abc"
    var value = 123

    override init() {
        super.init()
    }
}

因此,我需要保留一个类型为 的变量[Presets]。我的首选项窗口中的视觉表示是一个NSTableView,绑定到一个NSArrayController

我按照教程设置绑定。运行应用程序并尝试添加新预设(通过单击+按钮)时,出现以下错误:

[User Defaults] Attempt to set a non-property-list object (...) as an NSUserDefaults/CFPreferences value for key presets
[General] Attempt to insert non-property list object (...) for key presets

我已经尝试实现CodableandNSCoding协议,但错误仍然存​​在。

通过在 Stack Overflow 中搜索类似问题(例如thisthis),似乎解决方案将涉及NSKeyedArchiverand NSKeyedUnarchiver。如果您手动触发加载和保存,这看起来很简单。不幸的是,我看不到如何将这些类与NSUserDefaultsController.

标签: swiftcocoansuserdefaultscodablenscoding

解决方案


我通过子类化解决了这个问题,NSArrayController如下所示(见 Hamish 对我的另一个问题的评论,这是使这个通用的拼图的最后一个缺失部分):

extension Encodable {
    fileprivate func encode(to container: inout SingleValueEncodingContainer) throws {
        try container.encode(self)
    }
}

struct AnyEncodable: Encodable {
    var value: Encodable
    init(_ value: Encodable) {
        self.value = value
    }
    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        try value.encode(to: &container)
    }
}

class NSEncodableArrayController: NSArrayController {
    override func addObject(_ object: Any) {
        let data = try! PropertyListEncoder().encode(AnyEncodable(object as! Encodable))
        let any = try! PropertyListSerialization.propertyList(from: data, options: [], format: nil)

        super.addObject(any)
    }
}

推荐阅读