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!
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 Swift does not seem to work
let
statements don't have default initialization of optionals to nil, because otherwise writing let foo:Bar!
would give you a foo
that was always nil and you couldn't initialize it in a subsequent statement.
The reason var
is appropriate is that you want default initialization to nil to occur so you can initialize your City
object with the self reference in order to finally initialize your actual capitalCity
value which is really double initialization.
The code has a circular class dependency by design, so this is a side effect of that design.
This behavior of let
is new in Swift 1.2, try the example in Xcode 6.2 or earlier and you will find that it compiles.
Initialize a variable with nil vs implicitly unwrapped optional
Your code will simply not compile. Here's why.
By specifying var capitalCity: City
, you're explicitly saying that your variable is non-optional. It can only ever hold a valid City
. It can never be optional, so it can never hold nil
.
Meanwhile, anytime you use ?
or !
, you are defining an optional type. These can be nil, and in fact are nil
by default.
So in your example from the guide, var capitalCity: City!
is saying the following:
capitalCity
is declared as an implicitly unwrapped optional type (the!
), meaning that you, as the developer, are declaring it to always have a validCity
type whenever it is called.- That said, until you set a
City
to it, it defaults to beingnil
.
When you should use optionals comes down to how you want to use your properties. In the original example, from what little we see, capitalCity
is only set in the class init. So there wouldn't be a reason for it to be optional. So for that example, it could exist like the other property: let capitalCity: City
.
A lot depends on how you want the properties to exist and work when you're using your object. For instance, making something optional signals at least two things:
- The property may not have a valid value in the class' lifecycle.
- You may not be setting it when you initialize your class. (Remember, an optional initializes to
nil
)
I hope this helps you understand optionals some more.
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.
Difference between Force Unwrapping Optionals and Implicitly Unwrapped Optionals
First of all let's define an Optional
An Optional value is a container of some type (Int
, String
, UIColor
, ...), it could contain the value (1
, "Hello world"
, .greenColor()
, ...) or nil
.
let anOptionalInt: Int? = 1
let anotherOptionalInt: Int? = nil
When in Swift we see an Optional value we think:
Ok this could contain the actual value or
nil
Force unwrapping
It's the action of extracting the value contained inside an Optional
.
This operation is dangerous because you are telling the compiler: I am sure this Optional value does contain a real value, extract it!
let anOptionalInt: Int? = 1
let anInt: Int = anOptionalInt!
Now anInt
contains the value 1.
If we perform a force unwrapping on an Optional value that happens to contain nil
we get a fatalError
, the app does crash and there is no way to recover it.
let anotherOptionalInt: Int? = nil
let anotherInt = anotherOptionalInt!
fatal error: unexpectedly found nil while unwrapping an Optional value
Implicitly unwrapped optionals
When we define an Implicitly unwrapped optional, we define a container that will automatically perform a force unwrap each time we read it.
var text: String! = "Hello"
If now we read text
let name = text
we don't get an Optional String
but a plain String
because text
automatically unwrapped it's content.
However text is still an optional so we can put a nil
value inside it
text = nil
But as soon as we read it (and it contains nil
) we get a fatal error because we are unwrapping an optional containing nil
let anotherName = text
fatal error: unexpectedly found nil while unwrapping an Optional value
Related Topics
Cross Platform Aes Encryption Between iOS and Kotlin/Java Using Apples Cryptokit
Swift, Sprite Kit Game: Have Circle Disappear in Clockwise Manner? on Timer
Possible to Pass an Enum Type Name as an Argument in Swift
Swift 3 String Contains Exact Sentence/Word
How to Convert Uint16 to Uint8 in Swift 3
Fblpromises Framework Not Found
Swift: Using "/" Slash in Filename with Createdirectoryatpath
How to Save the Attributed String (Text) into File (Swift, Cocoa)
How to Get Coreml in Pure Playground Files
No Code Signature Found After Pod Installed in Xcode 8
Build Input File Cannot Be Found' Swift 4.2, Xcode 10.0
iOS 11 Large Title Navigation Bar Snaps Instead of Smooth Transition
Fill Circle with Wave Animation in Swiftui
How to Use Println in Swift to Format Number
How to Shuffle an Array So That No Two Consecutive Values Are the Same