问题
I am trying to save an array of optionals Strings to NSUserDefaults, but unfortunately it doesn't work:
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?'
}
回答1:
[String?] is a Swift type that cannot be represented as a Foundation type. Normally, Swift Array bridges to NSArray, but an NSArray cannot contain nil. An Array of Optionals can contain nil, so it doesn't bridge automatically.
You could work around this by using a sparse array representation. (And since your content is strings — a property list type and therefore legal for use in NSUserDefaults — you don't even need to use NSCoding to encode the array.) A dictionary makes a pretty good sparse array:
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")
}
Then, when you go to read in your data from defaults, convert from the sparse-array dictionary form to the array-of-optionals form. That's a little bit more fun because you need to figure out from the sparse representation how many nils you need the array to store.
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($0)}).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
}
}
(Alternately, you might know that count is constant because it's, say, the number of text fields in your UI.)
回答2:
Let's say this is the original array
let textFieldEntries: [String?]
First of all let's turn the array of String? into an array of String.
let entries = textFieldEntries.flatMap { $0 }
Now we can save it
NSUserDefaults.standardUserDefaults().setObject(entries, forKey: "entries")
And retrieve it
if let retrieved = NSUserDefaults.standardUserDefaults().objectForKey("entries") as? [String] {
// here your have your array
print(retrieved)
}
来源:https://stackoverflow.com/questions/34052391/swift-storing-array-of-optionals-to-nsuserdefaults