1

I noticed that some coding examples for Swift declare optional properties in different ways. However, I seem to have trouble trying to tell them apart (or, rather, when to use each.)

class MyClass {
   // I believe this can start as nil but should always be set
   // once it is.
   var optionalProperty1: Type!

   // I believe this can be set or nil anytime.
   var optionalProperty2: Type?

   // I think this is the same as
   // var optionalProperty3: Type!
   lazy var optionalProperty3: Type
}

How does each one differ from the others and when should each one be used?

4 Answers4

2

var optionalProperty1: Type!

When you're sure you will have value for this property such as timestamp it will be something for sure. And Yes it can be nil too.

var optionalProperty2: Type?

When you're not sure about the value (Or this field is not mandatory) take it as optional for example:- If I make a Person class address can be optional and name will not.

lazy var optionalProperty3: Type

This syntax is wrong you can not declare lazy property in this way. You must assign something to it initially. See below example:

/// First way
lazy var optionalProperty3: String = {
    return "Hello"
}()

/// Second way
lazy var optionalProperty4 = "Hello"

A lazy stored property is a property whose initial value is not calculated until the first time it is used. You indicate a lazy stored property by writing the lazy modifier before its declaration. lazy variables are great for things that need to be setup once, then never re-set.

One more thing you really don't need to specify type in modern Swift. Means if you will assign 0 it will be an integer itself, if you will assign 0.0 it will take it as double and same for String, Array etc.

TheTiger
  • 13,264
  • 3
  • 57
  • 82
  • I'd argue 1 & 2 are used respectively when you want a crash if the value is nil and when you want the application to continue if the value is nil. The main use of optionals is tracking down bugs and deciding which values need to be valid for the application to continue in a valid state. It's comparable to the difference between putting a function call in a try-catch, and letting the calling method throw further up. – kevin May 15 '18 at 08:22
  • `var optionalProperty1: Type!` can also be `nil` and you can also check `if optionalProperty1 == nil`. Although there are several thinking to get the benefits from an `optional` property. – TheTiger May 15 '18 at 08:27
0

The third declaration is not an optional.

The third one declares a lazy property. Lazy properties will only be initialised when they are first used. Example:

class A {
    lazy var a: Int = {
        print("hello")
        return 1 + 1
    }()
}

let a = A()
print(a.a)

If you remove the last line, hello will not be printed.

The first declaration is a implicitly unwrapped optional while the second declaration is a normal optional.

When you access members of a normal optional, you need to unwrap it with ? or !:

var myInt: Int? = ...
print(myInt.description) // doesn't compile, must unwrap
print(myInt!.description) // will crash if myInt is nil
print(myInt?.description) // will print "nil" if myInt is nil

On the other hand, implicitly unwrapped optionals do this implicitly - whenever you try to access a member, it will implicitly unwrap it with ! for you:

var myInt: Int! = ...
print(myInt.description) // equivalent to "myInt!.description"
Sweeper
  • 213,210
  • 22
  • 193
  • 313
0

From Apple's Swift documentation:

Optionals (?): "You use optionals in situations where a value may be absent. An optional represents two possibilities: Either there is a value, and you can unwrap the optional to access that value, or there isn’t a value at all."

Implicitly Unwrapped Optionals (!): "As described above, optionals indicate that a constant or variable is allowed to have “no value”. Optionals can be checked with an if statement to see if a value exists, and can be conditionally unwrapped with optional binding to access the optional’s value if it does exist.

Sometimes it’s clear from a program’s structure that an optional will always have a value, after that value is first set. In these cases, it’s useful to remove the need to check and unwrap the optional’s value every time it’s accessed, because it can be safely assumed to have a value all of the time.

These kinds of optionals are defined as implicitly unwrapped optionals. You write an implicitly unwrapped optional by placing an exclamation mark (String!) rather than a question mark (String?) after the type that you want to make optional.

Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter. The primary use of implicitly unwrapped optionals in Swift is during class initialization, as described in Unowned References and Implicitly Unwrapped Optional Properties."

Read more at https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html

rodskagg
  • 3,827
  • 4
  • 27
  • 46
0

Explicitly Unwrapped Variable

var optionalProperty1: Type!

This means that the value should never be nil. It will always be initialized but it is better to use var optionalProperty1: Type

Optional

var optionalProperty2: Type?

This is an optional value, meaning that it can either have a value or be nil. normally to use the value you would need to unwrap it. using either conditional unwrapping or a guard statement...

if let value = optionalProperty2 {
    print("optionalProperty2 had a value, value is set")
}

guard let value = optionalProperty2 else {
   print("optionalProperty2 was nil value is nil") 
}

or you can just check if it has a value and explicitly unwrap it (which is not considered best practice)

if optionalProperty2 != nil {
    print("optionalProperty2 is set to \(optionalProperty2!)")
}

Lazy Variable

lazy var optionalProperty3: Type a lazy variable is different, it is not an optional unless you define it to be optional. Lazy variables do not initialise to a value until the value is first used. So if you do not call/use the variable it will never be set.

Scriptable
  • 19,402
  • 5
  • 56
  • 72