Friday, July 18, 2014

Can I skip Optionals?

TL;TR: NO!
Working with Swift but using Cocoa/CocoaTouch API, you will have to get a good grasp on what they are and how to use them. When an Objective-C API returns nil, Swift will receive an Optional set to the value NONE.

Quick definition

A definition by example:
var optionalString: String?
optionalString == nil
// Non optional values needs to be initialised before using them. 
var string: String = "Test String"
string == "Test String"
Optionals is an enum to say "I have something" or "it's empty". You can picture it as a box which can be empty or contain something. It's just a box, to know what's inside you need to unwrap it. When defining an optional type, use ?, when unwrapping it, use !. Note that ? and ! are short name for Optional and ImplicitlyUnwrappedOptional.

To unwrap or not to unwrap?

When do we want to unwrap them? Work with them as much as you can in their Optional form, unwrap them when you need to work with their value.
// An optional is sth or nothing, you can not compute operation with optional
// you need to unwrap them
var i: Int?
var j: Int?
//var k = i + j     // compilation issue
//var k = i! + j!   // no compilation issue but runtime issue if i/j not initialised
But the confusion is that most of the time, operating on optionals required unwrapping... except for println and string interpolation. the exception to confirm the rule, would say linguist ;)
 
var kitty: String? = "Kitty"
var greeting = "Hello \(kitty)"     // No compiler error!
print("Hello"); println(kitty)      // Also fine.
var nope = "Hello " + kitty         // Compiler error


Different ways of unwrapping

Several way of unwrapping:
  • either go the brute way, unwrap without checking and risk a runtime error
  • or check before with if statement, you can even use the if let or if var statement
  • or go with optional chaining with elvis operator ?. (turn your head left to see Elvis, remind me Groovy syntax here)
// 1. force unwrapped
var optionalValue: String?
// optionalValue! // no compilation issue but runtime issue because optionaValue is nil

// 2. if let: unwrap with
var optionalName: String?
var hello = "Hello!"
if let name = optionalName {
    hello = "Hello, \(name)" // not executed
}
optionalName = "John Appleseed"
hello = "Hello, \(optionalName)"

if let name = optionalName {
    hello = "Hello, \(name)" // executed
}

// Same idea with for
var jsonResponse: [String:String?] = ["one":"onevalue", "two":nil]
var str:String?
for (key, value) in jsonResponse {
    str = "key \(key) value \(value)"
}
str // Some "key one value onevalue"

// 3. optional chaining
// do not unwrap optionals if not needed, work with them 
if let a = call1() {
    if let b = a.call2 {
        if let c = b.call3 {
            // do sth
        }
   }
}
let c = call1()?.call2?.call3


Working with implicitly unwrapped optionals

Implicitly unwrapped optionals can be nil same than normal optional, but they are automatically unwrapped when used. As per unwrap optional you may run into runtime error.
func toInt(first:String!) -> Int! {
    return Int(first.toInt()!)
}
var myIn:Int = toInt("3")
// var myIn:Int = toInt("3e") // runtime error


Try it yourself

Have a go with Optionals Playground format and Happy Swift coding!

No comments:

Post a Comment

Note: Only a member of this blog may post a comment.