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.
How to use guard statement to detect nil after an assignment?
The other answers show you how to solve your issue, but doesn't really explain why this error occurs, so I thought I'd pitch in on that.
The guard let ... else
statement, much like if let ...
, attempts to bind the unwrapped value of an optional---generally as long as this is not nil
---to a non-optional immutable of the same underlying type; using optional binding
var a: Int? = 5
if let b = a {
// b unwrapped, type inferred to non-optional type Int
print(b) // "5"
}
The above binding would fail if a
had the value nil
, as b
, as per default (by type inference), is of type Int
which cannot hold nil
.
In this context, it makes no sense to explicitly declare b
to be an implicitly unwrapped optional, as this will allow a successful binding even if a
is nil. An equivalently non-sense block would be to explicitly declare b
to be an optional, whereafter the "attempted optional binding" of optional a
(Int?
) to optional b
(Int?
) would naturally always succeed, and the if let ...
block reduces to a completely redundant block-local assignment.
a = nil
if let b: Int! = a {
print(b) // "nil"
// wups, we managed to bind a to b even though a is nil ...
// note also this peculiarity
print(b.dynamicType) // Optional<Int>
let c: Int! = nil
print(c.dynamicType) // ImplicitlyUnwrappedOptional<Int>
}
if let b: Int? = a {
print(b) // nil
// wups, we managed to bind a to b even though a is nil ...
}
Note the peculiarity that no matter if we explicitly specify b
to be of type Int?
(optional) or type Int!
(implicitly unwrapped optional), the binded immutable b
passing into the if let
block is, for both cases, just a regular optional (of type Int?
). This explains why you need to unwrap event
(event!.iconImgData
) after the guard let
clause, even though we declared it to be of an implicitly unwrapped type.
Hence, in your example, your guard let ... else
statement will not catch cases where eventsImagesLoading.removeValueForKey(location)
is nil
, as the binding to event
(which is of implicitly unwrapped optional type Event!
) will success even for nil
cases.
func foo() {
let bar : Int? = nil
guard let _: Int! = bar else {
print("this is surely nil")
return
}
print("but an implicitly unwrapped optional will fall through")
}
foo() // "but an implicitly unwrapped optional will fall through"
You should generally only use implicitly unwrapped optionals for immutables where you need delayed initialization (value nil
until initialized). After initialization of an implicitly unwrapped optional, its value should never be nil
(whereas in the example above, it's value is, after initialization by optional binding, just that; nil
).
Also, you should generally let the compiler infer the non-optional type of the immutable to which you are trying to bind in the guard let INFER_THIS = ... else
or if let INFER_THIS = ...
clauses.
We could ponder over whether it should even be allowed to use optional binding to optional types (guaranteed success), but that is another discussion.
Initialize instance variables inside instance function
This occurs because
var someVar: Footer!
does not define a variable of type Footer
but a variable of type Optional<Footer>
that is implicitly unwrapped. The code:
var someFooter: Footer!
bind(footer: &someFooter)
is logically equivalent to
var someFooter: Footer?
guard let tempFooter = someFooter? else { fatalError() }
bind(footer: &tempFooter)
As you can see, tempFooter
is a let, so it can't be passed as an inout variable and even if it could, the result would be thrown away.
You can fix this in one of three ways:
make the parameter to bind an optional, e.g.
func bind(footer: inout Footer?)
or use Martin's syntax to make it implicitly optional.Force the unwrap yourself:
var unwrapped: Footer = someFooter
bind(footer: unwrapped)
someFooter = unwrappedredesign the API. It seems the first thing you do in the
bind
function is overwrite the old footer with a newly initialised footer. So don't use an inout parameter, return the value you want i.e.func bind() -> Footer
{
var theFooter = Footer(...) { ... }
// do stuff
return theFooter
}
someFooter = bind()
I think the last option is the best in this case.
Swift 'if let' statement equivalent in Kotlin
You can use the let
-function like this:
val a = b?.let {
// If b is not null.
} ?: run {
// If b is null.
}
Note that you need to call the run
function only if you need a block of code. You can remove the run
-block if you only have a oneliner after the elvis-operator (?:
).
Be aware that the run
block will be evaluated either if b
is null, or if the let
-block evaluates to null
.
Because of this, you usually want just an if
expression.
val a = if (b == null) {
// ...
} else {
// ...
}
In this case, the else
-block will only be evaluated if b
is not null.
Related Topics
How to Subclass a Class Which Doesn't Have Any Designated Initializers
Make a Type Itself -- Not Its Instances -- Conform to a Protocol
Gcd Pattern for Chaining Async Operations While Piping the Results
Is a Static Boolean a Reference Type in Swift
How to Make Embedded View Controller Part of the Responder Chain
Replacement for _Stdlib_Getdemangledtypename() in Swift 2.2
iOS Swift: Unsafemutableaddressor Crash on iOS 8
Add Skin Tone Modifier to an Emoji Programmatically
Swift Pattern Matching with Enum and Optional Tuple Associated Values
How to Override Private Method and Call Super in Swift
@Objc Redundancy When Having @Objcmembers Private Dynamic Var
Nswindow with Round Corners in Swift
How to Suppress Warnings in Swift 3
Ckcontainer.Discoverallidentities Always Fails
Multidimensional Dictionaries Possible in Swift
Swift Build Error_If_Any_Output_Files_Are_Specified_They_All_Must_Be
How to I Turn Off the Ambient Light in Scene Kit (With Swift)