Search code examples
xcodeswifttype-conversionoption-typeoptional-values

How do I convert a contained forced value to a contained optional value?


Converting an optional value to a forced value works fairly simply:

    var aString: String? = "Hello"

    var anotherString: String = aString!

And it's even more simple in the opposite direction, because there's no unwrapping:

    var myString: String = "Hello"

    var myOtherString: String? = myString

It's a little more complicated to convert a forced value array containing optional values, to a forced value array containing forced values:

    var anArray: Array<String?> = ["Hello"]

    var anotherArray: Array<String> = anArray as Array<String>

What's a little different here is that you don't need the ! to unwrap the value. You're only telling it what type to expect.

Here's where I get stuck. Doing the opposite, to me, should look like this:

    var myArray: Array<String> = ["Hello"]

    var myOtherArray: Array<String?> = myArray as Array<String?>

But this gives the error:

'String' is not identical to 'String?'

Put simply as this, it gives the same error:

var myOtherArray: Array = myArray

I thought I had a fair grasp on this, but now I'm left unsure. How do I convert a contained forced value to a contained optional value (short of using a recreational for-loop)?

The recreational for-loop (not ideal):

    var myArray: Array<String> = ["Hello"]

    var myOtherArray: Array<String?> = []

    for loopString: String in myArray {
        myOtherArray.append(loopString)
    }

Solution

  • You have to create a new array by converting each element to an optional. But instead of a for-loop, you can use map():

    var myArray = ["Hello"]
    var myOtherArray = map(anotherArray) { Optional($0) }
    println(myOtherArray) // [Optional("Hello")]
    

    And your method for converting the other way around

    var anArray: Array<String?> = ["Hello"]
    var anotherArray: Array<String> = anArray as Array<String>
    

    aborts with

    fatal error: can't unsafeBitCast between types of different sizes
    

    in my current Xcode 6.1. Using map() here works:

    var anArray: Array<String?> = ["Hello"]
    var anotherArray = map(anArray) { $0! }
    println(anotherArray) // [Hello]
    

    (Of course this will abort at runtime if any array element is nil.)