Lawrence413 Lawrence413 - 1 year ago 48
Swift Question

NSArray, NSUserDefaults, optionals and unwrapping mess

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

I have an

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
label.text = localArray[currentIndex+1]

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

And in
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
with a few strings. And everything worked fine. But once I added the user defaults, madness began. I had errors everywhere I used
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
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
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
method change.

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

Answer Source

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>
    //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.