Swift NSUserDefaults不能保存字典?

25

我有以下测试代码:

  func testSaveDictionary() {
    let userDefaults = NSUserDefaults.standardUserDefaults()
    var jo = [
      "a" : "1.0",
      "b" : "2.0"
    ]

    let akey = "aKey"
    userDefaults.setObject(jo, forKey: akey)
    var isOk = userDefaults.synchronize()

    var data0 = userDefaults.dictionaryForKey(akey)
    println(data0)

  }

println(data0)的输出是nil。

我的代码有什么问题吗?Swift字典现在或在最终版本中是否被视为属性列表?

5个回答

31

更新关于 Swift 2, Xcode 7: 正如@atxe指出的那样,NSUserDefaults字典现在映射为[String, AnyObject]。这是Objective-C“轻量级泛型”的结果,它允许将Objective-C方法声明为

- (NSDictionary<NSString *,id> *)dictionaryForKey:(NSString *)defaultName

(默认对象必须是属性列表,特别是字典的键只能是字符串。)

另一方面,如果可能的话,Swift字典会自动桥接,因此问题中的原始代码可以正常工作:

let jo = [
    "a" : "1.0",
    "b" : "2.0"
]

let akey = "aKey"
// Swift 2:
userDefaults.setObject(jo, forKey: akey)
// Swift 3:
userDefaults.set(jo, forKey: akey)

Swift 1.2 的原始答案: 用户默认设置可以存储 NSDictionary 对象,这些对象在 Swift 中被映射为 [NSObject : AnyObject]

var jo : [NSObject : AnyObject] = [
    "a" : "1.0",
    "b" : "2.0"
] 
userDefaults.setObject(jo, forKey: akey)
var isOk = userDefaults.synchronize()

请注意,dictionaryForKey() 返回一个可选类型(optional),所以你应该通过一个可选类型的赋值来进行检查:

if let data0 = userDefaults.dictionaryForKey(akey) {
    print(data0)
} else {
    print("not set")
}

// Output: [b: 2.0, a: 1.0]

2
没错!关键是要明确声明:var jo: [NSObject: AnyObject],就像你之前提到的那样。 - Sean
另一种解决方法(如果由于某种原因您无法明确声明)是使用“as NSDictionary”:userDefaults.setObject((jo as NSDictionary), forKey: aKey)。 - winterized
1
在Swift 2.0中,NSUserDefault字典被映射为[String:AnyObject]。实际上,如果您尝试保存具有Int(例如)作为键的字典,则会在运行时失败。您可以定义带有强类型方法的扩展来安全支持并避免可能的运行时错误,尽管由Apple提供这样的微不足道的方法会很不错。 - atxe
我建议您编辑答案,将Swift 2.0版本放在最上面。 - xinatanil
特别是字典键只能是字符串,这解决了我的UserDefaults崩溃问题。谢谢! - BallpointBen

12

您需要先将其转换为NSData。像这样:

var data = NSKeyedArchiver.archivedDataWithRootObject(jo)
var userDefaults = NSUserDefaults.standardUserDefaults()
userDefaults.setObject(data, forKey:akey) 

4
我昨天遇到了这个问题并且发了一个雷达请求:iOS8中无法在NSUserDefaults中存储字典。该问题仅与iOS 8相关。并且我为这种情况描述了一种解决方法:在NSUserDefaults中保存字典的解决方法。它完美地解决了这个问题。
/// Save
NSUserDefaults.standardUserDefaults().setObject(NSKeyedArchiver.archivedDataWithRootObject(object), forKey: key)

/// Read
var data = NSUserDefaults.standardUserDefaults().objectForKey(key) as NSData
var object = NSKeyedUnarchiver.unarchiveObjectWithData(data) as [String: String]

3
“Workaround for saving dictionary in NSUserDefaults”的链接已失效。” - Carl Smith

3

请按照下面的优美代码进行操作 -> Swift 3

public func setDict(dict: NSDictionary) {
    let data = NSKeyedArchiver.archivedData(withRootObject: dict)
    let userDefaults = UserDefaults.standard
    userDefaults.set(data, forKey:"keyHere")
}


public func getDict() -> NSDictionary {
    let data = UserDefaults.standard.object(forKey: "keyHere") as! NSData
    let object = NSKeyedUnarchiver.unarchiveObject(with: data as Data) as! NSDictionary
    return object;
}

1

//swift 4.0

//用于保存

    let userDefaults = UserDefaults.standard
    userDefaults.setValue(value, forKey: "Your_Key")
    userDefaults.synchronize()

//用于检索的for循环

        let loadedCart = UserDefaults.standard.dictionary(forKey: "Your_Key")

1
根据我的理解,调用userDefaults.synchronize()的原因非常少。 - Johan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接