What is Swift's Yolo❗️ operator? Simply put, this is the bang ❗️ operator used to force-unwrap optionals. We've all done it -- don't lie. When practicing safe yolo, the Yolo❗️ operator can be a fun, healthy way to write code. So are you practicing safe yolo?

Why "Yolo"?

When an optional variable is force-unwrapped "unsafely", we are telling the compiler "Hey bro, don't worry about this code -- I know better than you do. Yolo. ¯\(ツ)/¯" This is the programming equivalent of "here, hold my beer -- watch this". You will get to know this line of code shortly because there is an excellent chance you will see it again in a crash report with the name EXC_BREAKPOINT.

Types of Yolo❗️

I can see those of you reaching around for your exclamation-shaped pitchforks already. Calm down. As with all things in life, there are exceptions in addition to best practices.

💥 Unsafe Yolo

Unsafe yolo is force-unwrapping optionals because you "need a non-optional" or "this will never be nil". If it will "never be nil", then make it a non-optional -- it's an optional for a reason. Using yolo unsafely should be met with the assumption that when something goes wrong, the "expected behavior" is to crash. Good thing you know every single failure path in your application, because you've just opted the compiler out of caring about it.

⚠️ Safe Yolo

"Safe" yolo is using force-unwrap in places where the only reason it should crash your application is because of a programming or "developer" error. It is a contractual agreement you are entering into with the compiler that you know what's up. A calculated risk.

Mitigated Yolo

Mitigated yolo is yolo that has been removed in favor of proper use of either formally optional/non-optional storage. This allows the compiler to completely fact-check your work automatically, at least for expectations around object initialization. Normally these cases require explicit error handling around "failure" cases when optionals are nil.

😱 Silent Yolo

Mitigated yolo cases in which a formal optional has been used, but your nil failure cases are left entirely un-handled.

Yolo❗️ by Example

Storyboard Unpacking

Let's get this one out of the way since it's going to come up.

@IBOutlet weak var MyButton: UIButton❗️

When you create an IBOutlet from a storyboard or a xib, Xcode will create this little gem.

⚠️ This is as "safe" yolo as you are going to get as the storyboard unpacking system has more knowledge about the system it is building than the compiler does. If these variables are nil when you try and access them, there are only a few possibilities:

  1. You are accessing them before awakeFromNib has been called
  2. You didn't connect that IBOutlet to your storyboard

These are both programmer errors and should crash your application.

Rogue Optionals

func completionCallback(optionalObject: Any?, error: ErrorType?) {
    guard error == nil else {
        // handle the error
        return
    }

    // do some processing
    self.nonOptionalFunc(optional❗️)
}

Someone (of course not you) has indicated that some variable is "optional" and you want to pass it into a function that requires a non-optional parameter.

Let's mitigate this by using if let and explicitly handling both logical branches:

func completionCallback(optionalObject: Any?, error: ErrorType?) {
    guard error == nil else {
        // handle the error
        return
    }

    if let unwrappedOptional = optional {
        // do some processing
        self.nonOptionalFunc(unwrappedOptional)
    } else {
        // explicitly handle this case since something clearly went wrong
    }
}

Inline optionals

let width: CGFloat = self.imageCache.imageForKey(imageKey)❗️.size.width

This is likely the most common occurrence of yolo in your codebase. Something will break here at some point in the future. Go on, do a quick audit of your codebase for !.. I'll wait.

Many yolos

Unfortunately, you're probably not going to like this one very much. Depending on how important or "required" the result of the work you are performing, you'll have to handle it in a couple of different ways:

Explicitly handle the failure

let width: CGFloat
if let cachedImage = self.imageCache.imageForKey(imageKey) {
    width = cachedImage.size.width
} else {
    // Handle "failure" here
}

😱 Silently -- "don't care yolo"

var width: CGFloat = 0.0
if let cachedImage = self.imageCache.imageForKey(imageKey) {
    width = cachedImage.size.width
}

Weak Storage

weak var delegate: UITableViewDelegate❗️

When defining storage properties using weak storage, you should never* yolo these properties. weak storage are auto-zeroing properties that can become nil at any time when their owners release them.

You are entering into a contract with the compiler that you cannot in any way fulfill without intimate knowledge of the owner of delegate.

This is a no-yolo situation that should be handled correctly with optionals:

weak var delegate: UITableViewDelegate?

Type Casting

let superObject = (givenObject as❗️ MyObject)

⚠️ This pattern could qualify as an expected cautious-yolo and could be a programmer error depending on your requirements. If your object doesn't get cast correctly, we want it to crash. If you're already at this point, it will likely require much more code to completely obviate the yolo altogether.

The other option is to if let the type cast and handle the "failure" depending on your architecture and requirements.

if let superObject = givenObject as? MyObject {
    // guaranteed superObject is MyObject and non-optional
}
else if superObject == nil {
   // superObject was nil -- but we didn't crash!
} else {
    // givenObject was non-nil , but failed a cast to MyObject -- handle failure depending on requirements
}

Throwing Errors

try❗️ errorThrowingProcessing(ofObject: obj)

Even if this is "temporary" code -- both you and I know this will make it into production. You're entering into a contract here where failures that result from this function choking will be met with an application crash.

Properly handle the error flow

do {
    try errorThrowingProcessing(ofObject: obj)
}
catch {
    // Handle error or rethrow -- it was thrown for a reason
}

⚠️ The safe yolo path here would be that the application should crash. Instances such as unpacking a resource from the bundle. If it doesn't exist, the bundle has in some way been damaged.

let resource = try❗️ unpackCriticalBundledResourceWithName(resourceName)

* unless you seriously know what you're doing and have written a lot of documentation around this code. judicious use of emoji is recommended with this type of documentation