问题
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