3

How can I do an optional binding in Swift and check for a negative result? Say for example I have an optional view controller that I'd like to lazy load. When it's time to use it, I'd like to check if it's nil, and initialize it if it hasn't been done yet.

I can do something like this:

if let vc = viewController? {
   // do something with it
} else {
   // initialize it
   // do something with it
}

But this is kludgey and inefficient, and requires me to put the "do something with it" code in there twice or bury it in a closure. The obvious way to improve on this from objC experience would be something like this:

if !(let vc = viewController?) {
   // initialize it
}
if let vc = viewController? {
   // do something with it
}

But this nets you a "Pattern variable binding cannot appear in an expression" error, which is telling me not to put the binding inside the parenthesis and try to evaluate it as an expression, which of course is exactly what I'm trying to do...

Or another way to write that out that actually works is:

if let vc = viewController? {

} else {
   // initialize it
}
if let vc = viewController? {
   // do something with it
}

But this is... silly... for lack of a better word. There must be a better way!

How can I do an optional binding and check for a negative result as the default? Surely this is a common use case?

Eric Rowe
  • 53
  • 1
  • 5

3 Answers3

4

you can implicitly cast Optional to boolean value

if !viewController {
    viewController = // something
}

let vc = viewController! // you know it must be non-nil 
vc.doSomething()

Update: In Xcode6-beta5, Optional no longer conform to LogicValue/BooleanType, you have to check it with nil using == or !=

if viewController == nil {
    viewController = // something
}
Bryan Chen
  • 45,816
  • 18
  • 112
  • 143
  • There is no such thing as "implicitly cast to boolean". `!` operates on any type conforming to `LogicValue` (now `BooleanType`). `Optional` used to conform to `LogicValue`, but no longer. – newacct Aug 05 '14 at 02:59
2

Would this work for you?

if viewController == nil {
  // initialize it
}

// do something with it
MirekE
  • 11,515
  • 5
  • 35
  • 28
  • Yes, this would work too... I was wrapped around the axle looking for a way to do it with optionals, and the obvious was staring me right in the face! I wonder which way was the intent of the designers? – Eric Rowe Aug 04 '14 at 13:35
0

One way might be to create a defer statement that handles the actions. We can ensure those actions occur after the creation of our object by checking for nil. If we run into nil, instantiate the object and return. Before returning our deference will occur within the scope of some function.

func recreateAndUse() {

  defer {
    viewController?.view.addSubview(UIView())
    viewController!.beginAppearanceTransition(true, animated: true)
  }

  guard viewController != nil else {
    viewController = UIViewController()
    return
  }

}
jnblanchard
  • 1,182
  • 12
  • 12