Search code examples
iosarraysswiftnsarraynsuserdefaults

NSArray, NSUserDefaults, optionals and unwrapping mess


I have really nasty errors while working with something apparently simple.

I have an NSArray which I fill with words the first time the app launches.

Then at a certain point I want to use the array, so I declared another array inside the class:

var localArray = NSUserDefaults.standardUserDefaults().arrayForKey("array")!

Then I want to display a word in a label. And when a user presses a button (forward/backward) the next/previous word appears. Pretty simple, right? It is, but somehow I get really nasty errors.

I have 2 methods for the next/previous words:

    @IBAction func nextWord(sender: AnyObject) {
        if let currentIndex = localArray.indexOf(label.text!)
        {
            if currentIndex == localArray.count-1
            {
                label.text = localArray[0] as? String
            }
            else
            {
                label.text = localArray[currentIndex+1]
            }
        }
    }

The other method for going backwards is identical (with necessary modifications).

And in viewDidLoad I just set the label's text:

label.text = localArray[0] as? String

The problem is with the if let statements. Before using the user defaults, I just initialized localArray with a few strings. And everything worked fine. But once I added the user defaults, madness began. I had errors everywhere I used localArray saying that the array isn't unwrapped. So I added ! after the user defaults array when initializing the local one.

But the last 2 errors (in the if let statements) make no sense. Now the indexOf() method throws an error, a thing that didn't happen before. And it also tells me that it can't convert the string (label.text!) to @noescape (AnyObject) throws -> Bool.

So now I need to transform that string to an NSString for that to work or what? I found something about "bridging" related to arrays in user defaults. Is that my issue?

Now here's what bugs me: WHY do I have to explicitly downcast a string in the array to a string? WHY did the indexOf method change.

Doesn't an unwrapped optional act like a non-optional?


Solution

  • The object you are creating is not an array (at least the compiler doesn't know it is). The function arrayForKey("array")! is returning an AnyObject, not an Array. So from there on out the compiler thinks this object is an AnyObject. How I would solve this (may not be the correct way) would be to cast the Array immediately:

    if let myArray: AnyObject! = NSUserDefaults.standardUserDefaults().objectForKey("array") {
        //Your array exists, cast it now and use it
        var localArray =  myArray as! Array<String>
    }
    else
    {
        //Something bad happened, the array isn't there.
    }
    

    Then you will have to do unwrapping later on. If you know this object will always exist and the cast will always work you can change the ? to !.

    Look to this answer for a little more information.