Swift: Storing Array of Optionals to NSUserDefaults?

那年仲夏 提交于 2019-12-23 21:18:38

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!