If you drag an IBOutlet from a XIB or storyboard to your Swift file, XCode will generate an implicitly unwrapped optional by default.

@IBOutlet weak var label: UILabel!

At first you might think that’s totally OK. Those properties won’t be set in the initializer, but when the view loads. And since you’re usually not doing much with your view controller until it has a view nothing breaks.

And then you add handling of memory warnings and suddenly you get crashes!

Why that?

Consider the following very simple view controller:

class ChristmasViewController: UIViewController {
	
  @IBOutlet weak var label: UILabel!

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    if isViewLoaded() && view.window == nil {
      view = nil
    }
  }
	
  override func viewDidLoad() {
    super.viewDidLoad()
		
    label.text = "Happy Holidays!"
  }
	
  /// This method might be called at any time from other classes!
  func updateWithExternalString(str: String) {
    label.text = str
  }
}

As you can see the view is unloaded in case of a memory warning, since it can be recreated easily. Unfortunately there are other parts of the view controller that assume that the outlets are never nil - they are implicitly unwrapped so it’s not that obvious to the user of those properties or callers of public methods!

Similar things can happen if you use KVO or NSNotifications, which might be fired while your view is not present. Of course you can (and should!) also handle these cases by unregistering those observers when discarding the view.

To solve this problem, we as a team agreed on making those optionals real optionals. They are optional after all so lets use the features that Swift gives us.

The view controller from above might now look something like this:

class ChristmasViewController: UIViewController {
	
  @IBOutlet weak var label: UILabel?

  override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    if isViewLoaded() && view.window == nil {
      view = nil
    }
  }
	
  override func viewDidLoad() {
    super.viewDidLoad()
		
    guard let label = label
      else {fatalError("Outlets not correctly initialized!")}
		
    label.text = "Happy Holidays!"
  }
	
  /// This method might be called at any time from other classes!
  func updateWithExternalString(str: String) {
    label?.text = str
  }
}

Of course this adds guard statements and other checks but makes the semantic more obvious and clear. Also we now get better error messages in case something crashes. If we screwed up some outlet we get a message telling us exactly this.

In general I would recommend to avoid implicitly unwrapped optionals whenever possible. Sometimes they seem convenient, but there’s usually a more explicit and safer way of doing it!