Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When to use ?, !, None, or Lazy?

I just started learning Swift and recently found out about

  1. "Normal" variables (for lack of a better name):

    ex: var test1: String

  2. "Optional" variables

    ex: var test2: String?

  3. "Implicitly Unwrapped Optionals"

    ex: var test3: String!

  4. Lazy variables

    ex: lazy var test4: String

My understanding is this:

  1. Use "Optional" variables (?) when the variable may or may not be initialized at points in the future starting from initialization

  2. Use "Implicitly Unwrapped Optionals" (!) when the variable is guaranteed to be initialized

  3. Optionals can be converted to Implicitly Unwrapped Optionals via "Forced Unwrapping"

    ex: let possibleString: String? = "Hello" println(possibleString!)

  4. Use "Lazy variables" when there is no need for something to be set until initialization (it seems these can be used with (?) or (!))

Therefore, my questions are:

  1. When do I use option 1 - a variable without ? and without !

  2. When do I use "lazy"

  3. I read "lazy" is often used for singletons - why?

I have the most experience in Java and C++ terms, if that helps with my background for answering.

Edit: Here's everything I found (The main issue was "Normal" vs "Implicitly Unwrapped Optionals":

  1. "Normal" variables must be initialized: (a) On the same line, (b) in the same scope before usage (Usage means some operation with the object), (c) by the end of the init iff the variable is a field. Note: The scope of init is everything in the scope of the class AND not in the scope of functions within the class.
  2. Printing an Implicitly Unwrapped Optional will print "nil", but using the variable's functions will throw a runtime exception. Meanwhile, using (at all, including print) a Normal variable will not allow the program to compile at all
  3. The purpose of using ! over "" (Nothing) is (a) More leniency since the program will compile (and run correctly given the variable is actually initialized) and (b) Lets you not initialize everything at the very beginning. Note: It is a compile time error to have any field undeclared if it is a Normal variable.
like image 265
AeonNeo Avatar asked Jun 28 '15 07:06

AeonNeo


3 Answers

Not exactly that.

All variables must be initialised before the first use, and all class/struct stored properties must be assigned value in respective initialiser. Optionals are not about being allowed uninitalised at some point, but about being allowed to contain no value, which is represented by nil, which is still perfectly an initialised stated for such variable. Therefore, if something can not be known at the moment of initialisation then that's probably where you will use some sort of an optional (e.g. delegate for a view).

Implicitly unwrapped optionals is a sort of shorthand for cases when a variable might be empty, but we are absolutely sure that when we will be really using it it will hold an actual value (typical example is a property in a view controller that holds reference to a view).

Forced unwrapping does not convert optional into implicitly unwrapped optional, instead it gives you a value that is there if it's there (i.e. if optional is not nil), and throws an exception if it's not.

Lazy properties are used in cases when you want to defer their initialisation to a later stage, when the property is actually being used for first time. Usual case is if you need to access an expensive resource to do that (load huge file from disk, download it via network, etc), especially so if there might be cases when such property is not going to be used at all (why loading it from the disk if we will not use it probably?).

like image 61
0x416e746f6e Avatar answered Nov 14 '22 23:11

0x416e746f6e


let's see Apple's example

class Person {
    var residence: Residence?
}

class Residence {
    var numberOfRooms = 1
}

Residence instances have a single Int property called numberOfRooms, with a default value of 1. Person instances have an optional residence property of type Residence?.

If you create a new Person instance, its residence property is default initialized to nil, by virtue of being optional.

1. If you need default value for property to be nil - use optional. Using variable without ? and ! - like 'numberOfRooms' -

You can set the initial value of a stored property from within an initializer, as shown above. Alternatively, specify a default property value as part of the property’s declaration. You specify a default property value by assigning an initial value to the property when it is defined.

NOTE

If a property always takes the same initial value, provide a default value rather than setting a value within an initializer. The end result is the same, but the default value ties the property’s initialization more closely to its declaration. It makes for shorter, clearer initializers and enables you to infer the type of the property from its default value. The default value also makes it easier for you to take advantage of default initializers and initializer inheritance.

2. ! is used to access the value wrapped inside variable when it is not nil, and throws exeption otherwise. So, you can use ! in order to make mark for users of you class - 'this value will not be nil at the time you unwrap it'

3. Lazy variable is used when you want to init it later, not at the time of whole object creation but exactly at the time you ask getter for data. this is useful when property stores an array, for example:

lazy var players: [String] = {
        var temporaryPlayers = [String]()
        temporaryPlayers.append("John Doe")
        return temporaryPlayers
        }()

When should I use lazy initialization?

One example of when to use lazy initialization is when the initial value for a property is not known until after the object is initialized.

like image 45
Doro Avatar answered Nov 15 '22 00:11

Doro


Short explanation:

A non optional variable has always a value and can never be nil. The variable must be initialized in the init method or in the declaration line.

var a : String
var b = "bar"

init {
    a = "foo"
}

An implicit unwrapped optional variable must not be initialized in the init method or in the declaration line but is guaranteed to have always a value when it's used

var a : String!

func viewDidLoad() {
    a = "Hello"
    a += " world!"
}

An optional variable may have a value and is nil at declaration

var a : String?  // = nil

A lazy variable is initialized later at the moment it's used the first time

class foo {
  lazy var bar : String = {
    return "Hello"
    }()
}
like image 28
vadian Avatar answered Nov 15 '22 00:11

vadian