Best Practice using an Array of Strings with NSUse

2019-02-28 23:21发布

问题:

I'm having a bit trouble saving an array of strings to userDefaults. I have an Array of strings declaired in a class, with a property observer ment to sync to userDefaults. Furthermore, I want the array to be limited to a maximum of 5 Strings.

let userDefaults = NSUserDefaults.standardUserDefaults()

var suggestions: [String]! {
    didSet {
        var arrayEnd = suggestions.count
        if arrayEnd >= 5 {
            arrayEnd = 4
        }
        let newArray = Array(suggestions[0...arrayEnd])
        userDefaults.setObject(newArray, forKey: "suggestions")
        userDefaults.synchronize()
    }
}

func getSuggestionData() {
    if userDefaults.valueForKey("suggestions") != nil {
        self.suggestions = userDefaults.valueForKey("suggestions") as? [String]
    }
}

override func viewDidLoad() {
    super.viewDidLoad()

    getSuggestionData()
    suggestions.insert("someString", atIndex: 0)
    }
}

When i run this i get:

fatal error: unexpectedly found nil while unwrapping an Optional value

on the line where I try to insert a new object to the array. I have tried following the approach in this thread, but it didn't save anything to the list.

I'm new to swift, and optional-types aren't my strong side, maybe someone know what's wrong?

回答1:

As reading from user defaults could return nil values, use optional binding to be safe:

func getSuggestionData() {
  if let suggestionArray = userDefaults.objectForKey("suggestions") {
    self.suggestions = suggestionArray
  } else {
    self.suggestions = [String]()
  }
}

But I'd recommend to use an non-optional variable with a defined default value.

In AppDelegate of your app, override init() or insert the code to register the key/value pair.

override init()
{
  let defaults = NSUserDefaults.standardUserDefaults()
  let defaultValue = ["suggestions" : [String]()];
  defaults.registerDefaults(defaultValue)
  super.init()
}

Registering the default keys and values is the way Apple suggests in the documentation.

  • If no value is written yet, the default value (empty array) is read.
  • If there is a value, the actual value is read

Instead of the value observer of the variable suggestions implement a method to insert a new value, delete the last one and write the array to disk. There is no need to use optional binding because the array in user defaults has always a defined state.

let userDefaults = NSUserDefaults.standardUserDefaults()
var suggestions = [String]()

func insertSuggestion(suggestion : String)
{
  if suggestions.count == 5 { suggestions.removeLast() }
  suggestions.insert(suggestion, atIndex: 0)
  userDefaults.setObject(suggestions, forKey: "suggestions")
  userDefaults.synchronize()
}

func getSuggestionData() {
  suggestions = userDefaults.objectForKey("suggestions") as! [String]
}

override func viewDidLoad() {
  super.viewDidLoad()
  getSuggestionData()
  insertSuggestion("someString")
}

A side note:
never use valueForKey: rather than objectForKey: if you don't need explicitly the key-value-coding method.



回答2:

Hey Just try like this way.

var suggestions: [String] = Array() {

        didSet {
            var arrayEnd = suggestions.count
            if arrayEnd >= 5 {
                arrayEnd = 4
            }
            if arrayEnd > 0
            {
            let newArray = Array(suggestions[0...(arrayEnd-1)])
            userDefaults.setObject(newArray, forKey: "suggestions")
            userDefaults.synchronize()


            }

        }

    }


    func getSuggestionData() {
        if userDefaults.valueForKey("suggestions") != nil {
            self.suggestions = userDefaults.objectForKey("suggestions") as! Array
        }
    }


    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        getSuggestionData()

        if self.suggestions.count > 4
        {
            var str = "\(self.suggestions.count)"
            self.suggestions.insert(str, atIndex: self.suggestions.count)
        }

    }