Implicitlyunwrappedoptional in Init VS Later

Why create Implicitly Unwrapped Optionals, since that implies you know there's a value?

Consider the case of an object that may have nil properties while it's being constructed and configured, but is immutable and non-nil afterwards (NSImage is often treated this way, though in its case it's still useful to mutate sometimes). Implicitly unwrapped optionals would clean up its code a good deal, with relatively low loss of safety (as long as the one guarantee held, it would be safe).

(Edit) To be clear though: regular optionals are nearly always preferable.

Implicitly Unwrapped Optionals in Initialization - Swift

I'd stay away from implicitly unwrapped optionals unless there is a good reason to use them. Use non optional, when possible, otherwise optionals. Implicitly unwrapped are very dangerous if improperly used because they bypass the compiler check and generate runtime exceptions.

Non exhaustive list of cases when to use implicitly unwrapped:

  • when there's an API returning an implicitly unwrapped
  • to solve the Strong Reference Cycles Between Class Instances problem
  • when you have a class/struct property that (by design) will never be nil, but it cannot be set in the initializer

A typical case of the latter usage is in a UIViewController, when a property is initialized in the viewDidLoad method rather than in an initializer - it makes sense to use an implicitly unwrapped.

Do not use implicitly unwrapped in this cases:

  • because it's cool
  • because it lets you save a key press on the keyboard
  • when you are not 100% sure whether to use it or not

In your specific case, although the properties are instantiated in the initializator, they depend from the superclass initialization, so it makes sense to declare them as implicitly unwrapped.

Implicitly unwrapped optional from init!() in Swift 3.1

InitTest(text: "Hello!") returns an implicitly unwrapped optional,
which is an optional that is unwrapped if necessary. For example
you can access its properties without explicit unwrapping

let string = InitTest(text: "Hello!").text

or pass it to functions taking a (non-optional) InitTest argument:

func foo(_ x: InitTest) { }
foo(InitTest(text: "Hello"))

But the assignment

let testResult = InitTest(text: "Hello!")

makes testResult a regular ("strong") optional, see
SE-0054 Abolish ImplicitlyUnwrappedOptional type and Implicitly unwrapped optional assign in Xcode 8:

If the expression can be explicitly type checked with a strong optional type, it will be.

Actually I cannot think of a good reason to define an init!() method.

Implicitly Unwrapped Optional when a constant that cannot be defined during initialisation, But Error Comes

The important part is here:

City(name: capitalName, country: self)

You are definitely using self in the expression which is executed before the assignment to the property capitalCity.

If you want to use self in any of the expressions, it needs to be in the second phase of two phase initialization, which means all properties needs to be initialized before the usage of self.

With using var, Swift assigns a default initial value nil for the property capitalCity. So the property can be considered as "already initialized", so, you can use self after you have initialized another property name.

(You know giving nil to a let-constant of ImplicitlyUnwrappedOptional is ridiculous.)

By the way private(set) var is often used in similar cases:

    private(set) var capitalCity: City!

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

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?).

swift - Implicit unwrapped optionals

It's all related to the class initialization.

take Outlets for example they're force unwrapped because we know they will hold a value after initialization from the XIB or Storyboard but they will not be set before the class initialization.

A force unwrapped optional exits to tell the compiler I'm taking the responsibility to make sure this variable will be set before calling it.

in your example I don't think it makes sense to write:

let aString: String! = "this is a test string"

It should just be as you wrote:

let aString: String = "this is a test string"

It makes more sense to have:

var aString: String!

meaning you'll take ownership of this variable initialization (i.e making sure it's not nil)

What is the point of using implicitly unwrapped optional in this example?

All your concerns about misleading documentation are right.

Also, please note that in Swift 2.2 returning early from a failable initializer does work, even before all properties are initialized:

class Product {
let name: String
init?(name: String) {
if name.isEmpty { return nil }
self.name = name
}
}

Another change is that deinit is not called any more when returning nil from the failable initializer.

From Xcode 7.3 beta 2 Release Notes:

Inside a class, a designated initializer that is either failable (init?()) or throwing (init() throws) is allowed to exit before initializing all stored properties and calling super.init(). This behavior is supported, making designated initializers more consistent with convenience initializers. Convenience initializers can also fail before performing a self.init() delegation.

Is there a technical downside to using implicitly-unwrapped optionals but testing for nil vs optional binding?

There is indeed a simple reason, and it's one of the ones you listed: "better safety checking". Optional bindings keep the scope of the unwrap known to the compiler, whereas it's the programmer's responsibility to keep track of when you have or have not checked an implicitly unwrapped optional for nil.

With optional bindings:

let stringA:String? = nil // (or "ABC")

if let unwrappedStringA = stringA
{
let x:String = unwrappedStringA
}

accidentallyAttemptingToUse(stringA) // Compiler error! I see my mistake.

With implicit unwrapping:

let stringA:String! = nil // (or "ABC")

if(stringA != nil)
{
let x:String = stringA
}

accidentallyAttemptingToUse(stringA) // Runtime crash I might find in testing. Yuck.

What are IUOs good for?

Why have implicitly unwrapped optionals at all, then? They exist for basically one purpose: properties that will definitely have a value, but not until slightly after init, so they have to be optional. Often @IBOutlets fall into this category: you can trust them to have a value, and you don't want to be unwrapping them all the time, but they are not assigned at init, so you must make them optional. That is what implicitly unwrapped optionals are for.

Unwrapping to a variable of the same name

Your update, which tentatively suggests unwrapping optionals into variables with the same name, is actually excellent Swift style, and has been used by Apple early and often. Code is easier to read when you unwrap to variables of the same name, because you can track fewer (and better) names. Definitely embrace this!

let stringA:String? = nil // (or "ABC")

if let stringA = stringA
{
let x:String = stringA // Of *course* this is still named `stringA`;
// it's representing the same concept, after all.
}

Best place to unwrap optional instance properties--when created or when called?

A variable should be declared as implicitly unwrapped (using !) only when you will be assigning a value outside of an init but before all of your other code will access the variable, and the variable will definitely be given a value.

Typical examples of this are outlets in a view controller. The values are assigned after init but before all other code will make use of them. In this case awakeFromNib or viewDidLoad is a typical place for the initialization. Since all other code can safely assume the variable has a non-nil value, the use of the implicitly unwrapped variable makes sense.

For "normal" optionals (using ? in the declaration), you should never force-unwrap those value since the whole reason the variable is an optional is because it might be nil.

In these cases, always use conditional binding (if let) or optional chaining.

In your example, you will most likely setup the map view in the viewDidLoad method so declare it as var mapView: MGLMapView!. Then you can reference mapView like it's not an optional everywhere else in your code. Just make sure you don't attempt to access mapView before viewDidLoad initializes it.

Another option is to set up the property as a lazily loaded property. Then you don't need it to be declared with either ? or !.



Related Topics



Leave a reply



Submit