Swift:将可选数组存储到 NSUserDefaults?
Swift: Storing Array of Optionals to NSUserDefaults?
我正在尝试将可选数组 Strings
保存到 NSUserDefaults
,但不幸的是它不起作用:
var textFieldEntries: [String?]
...
func encodeWithCoder(aCoder: NSCoder!) {
aCoder.encodeObject(textFieldEntries, forKey: "textFieldEntries")
// prints error: Cannot convert value of type '[String?]'
// to expected argument type 'AnyObject?'
}
假设这是原始数组
let textFieldEntries: [String?]
首先让我们把String?
的数组变成String
的数组。
let entries = textFieldEntries.flatMap { [=11=] }
现在可以保存了
NSUserDefaults.standardUserDefaults().setObject(entries, forKey: "entries")
并检索它
if let retrieved = NSUserDefaults.standardUserDefaults().objectForKey("entries") as? [String] {
// here your have your array
print(retrieved)
}
[String?]
是 Swift 类型,不能表示为 Foundation 类型。通常,Swift 数组桥接到 NSArray
,但 NSArray
不能包含 nil。可选数组可以包含 nil,因此它不会自动桥接。
您可以使用稀疏数组表示来解决此问题。 (并且由于您的内容是字符串 — 属性 列表类型,因此在 NSUserDefaults
中使用是合法的 — 您甚至不需要使用 NSCoding
来编码数组。)字典使一个很好的稀疏数组:
var textFieldEntries: [String?] = ["foo", nil, "bar"]
func saveToDefaults() {
var sparseArray: [String: String] = [:] // plists need string keys
for (index, entry) in textFieldEntries.enumerate() {
if let e = entry {
sparseArray["\(index)"] = e
}
}
// sparseArray = ["0": "foo", "2": "bar"]
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(sparseArray, forKey: "textFieldEntries")
}
然后,当您从默认值读取数据时,将稀疏数组字典形式转换为可选数组形式。这更有趣一点,因为您需要从稀疏表示中计算出您需要数组存储多少个 nils。
func readFromDefaults() {
let defaults = NSUserDefaults.standardUserDefaults()
guard let sparseArray = defaults.objectForKey("textFieldEntries") as? [String: String]
else { fatalError("unepxected defaults key format") }
// count of the sparse array = index of highest key + 1
let count = sparseArray.keys.flatMap({Int([=11=])}).maxElement()! + 1
// wipe the old array to put nils in all the right places
textFieldEntries = [String?](count: count, repeatedValue: nil)
// fill in the values
for (strindex, entry) in sparseArray {
guard let index = Int(strindex)
else { fatalError("non-numeric key") }
textFieldEntries[index] = entry
}
}
(或者,您可能知道 count
是常数,因为它是 UI 中文本字段的数量。)
我正在尝试将可选数组 Strings
保存到 NSUserDefaults
,但不幸的是它不起作用:
var textFieldEntries: [String?]
...
func encodeWithCoder(aCoder: NSCoder!) {
aCoder.encodeObject(textFieldEntries, forKey: "textFieldEntries")
// prints error: Cannot convert value of type '[String?]'
// to expected argument type 'AnyObject?'
}
假设这是原始数组
let textFieldEntries: [String?]
首先让我们把String?
的数组变成String
的数组。
let entries = textFieldEntries.flatMap { [=11=] }
现在可以保存了
NSUserDefaults.standardUserDefaults().setObject(entries, forKey: "entries")
并检索它
if let retrieved = NSUserDefaults.standardUserDefaults().objectForKey("entries") as? [String] {
// here your have your array
print(retrieved)
}
[String?]
是 Swift 类型,不能表示为 Foundation 类型。通常,Swift 数组桥接到 NSArray
,但 NSArray
不能包含 nil。可选数组可以包含 nil,因此它不会自动桥接。
您可以使用稀疏数组表示来解决此问题。 (并且由于您的内容是字符串 — 属性 列表类型,因此在 NSUserDefaults
中使用是合法的 — 您甚至不需要使用 NSCoding
来编码数组。)字典使一个很好的稀疏数组:
var textFieldEntries: [String?] = ["foo", nil, "bar"]
func saveToDefaults() {
var sparseArray: [String: String] = [:] // plists need string keys
for (index, entry) in textFieldEntries.enumerate() {
if let e = entry {
sparseArray["\(index)"] = e
}
}
// sparseArray = ["0": "foo", "2": "bar"]
let defaults = NSUserDefaults.standardUserDefaults()
defaults.setObject(sparseArray, forKey: "textFieldEntries")
}
然后,当您从默认值读取数据时,将稀疏数组字典形式转换为可选数组形式。这更有趣一点,因为您需要从稀疏表示中计算出您需要数组存储多少个 nils。
func readFromDefaults() {
let defaults = NSUserDefaults.standardUserDefaults()
guard let sparseArray = defaults.objectForKey("textFieldEntries") as? [String: String]
else { fatalError("unepxected defaults key format") }
// count of the sparse array = index of highest key + 1
let count = sparseArray.keys.flatMap({Int([=11=])}).maxElement()! + 1
// wipe the old array to put nils in all the right places
textFieldEntries = [String?](count: count, repeatedValue: nil)
// fill in the values
for (strindex, entry) in sparseArray {
guard let index = Int(strindex)
else { fatalError("non-numeric key") }
textFieldEntries[index] = entry
}
}
(或者,您可能知道 count
是常数,因为它是 UI 中文本字段的数量。)