当字典键具有 Null 值时如何保存 NSUserDefaults

How do I save NSUserDefaults when dictionary key has a Null value

我有一个项目使用 SwiftForms。 有一个导航栏按钮执行将文本字段中的信息发送到 NSUserDefaults 的功能。但是如果我有一个空的 textField,应用程序会崩溃,但是当所有字段都被填写时数据会被保存。我是否只是在函数中添加一个检查以查找 NSNull?

func submit(_: UIBarButtonItem!) {
    let message = self.form.formValues()
    //message is [String : AnyObject]
    let userDefaults = NSUserDefaults.standardUserDefaults()
    userDefaults.setObject(message as Dictionary, forKey: "theMessage")
    print("\n Message Saved! \n")
    print(message)
} 

这是我在单击“保存”但未填写任何字段并且应用程序崩溃时遇到的错误:

Attempt to set a non-property-list object {
    birthday = "<null>";
    job = "<null>";
    lastName = "<null>";
    name = "<null>";
    segmented = "<null>";
    stepper = 20;
    textview = "<null>";
} as an NSUserDefaults/CFPreferences value for key theMessage

这是我填写所有字段后得到的结果 - 没有崩溃

 --- Message Saved! --- 

["segmented": 1, "job": Job, "lastName": Last, "birthday": 2016-07-01 22:00:12 +0000, "textview": Etiam porta sem malesuada magna mollis euismod. Vestibulum id ligula porta felis euismod semperac, vestibulum at eros., "stepper": 22, "name": First]

formValues returns NSNull 用于无法保存在 NSDictionary 中的空值,如 Paulw11 所述。

您可以使用此功能对其进行过滤。

let filtered = message.filter({!.isKindOfClass(NSNull)}).reduce([:]) { ( dic , e) -> [String:AnyObject] in
            var dic = dic
            dic[e.0 as! String] = e.1
            return dic
        }

然后将filtered保存在userDefaults

Swift class 现在是 UserDefaultsNSUserDefaults 是 Objective-C class)。然而,这并没有改变 Swift 不能在 class 中存储具有 nil 值的字典这一事实。因此,只需先将字典存档为Data

var someDictionary: [String: String?] = ["a": nil, "b": "beta"]

do {

    let data = try NSKeyedArchiver.archivedData(withRootObject: someDictionary, requiringSecureCoding: false)
    UserDefaults.standard.set(data, forKey: "someKey")

} catch let error {
    print(error)
}

要检索词典,只需取消存档即可:

if let def = UserDefaults.standard.object(forKey: "someKey") as? Data,
    let d = try? NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(def) as? [String: String?] {
    print(d) // ["a": nil, "b": Optional("beta")]
}

在上面的示例中,try? 关键字将结果作为可选项处理。如果您希望处理错误,请使用 do-try-catch 模式:

if let def = UserDefaults.standard.object(forKey: "someKey") as? Data {

    do {

        if let d = try NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(def) as? [String: String?] {
            print(d) // ["a": nil, "b": Optional("beta")]
        }

    } catch {
        print(error)
    }

}

您可以将任何对象写入磁盘,只要它符合 NSCoding 协议。