How to use guard statement to detect nil after an assignment? - swift

I'm trying to use guard statement to check against nil.
I'm puzzled why the following let it slip through and generate a BAD_EXEC error:
guard let event:Event! = eventsImagesLoading.removeValueForKey(location) else {
return
}
images[location] = responseData
event!.iconImgData = images[location]
I'm trying to check if "event" is nil after the method call. If it is it should just return. But in reality it slips through and crashes on the event!.iconImageData... line.

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.

Change Event! to Event (line 1) and event! to event (line 5).

guard let event:Event = eventsImagesLoading.removeValueForKey(location) else {
return
}
images[location] = responseData
event.iconImgData = images[location]

Related

"Implicitly unwrapped property" warning?

I have a class where I have a property like this:
var residenceId: Int!
When building with Xcode 10 and Swift 4.2 there are no issues. However, after installing Xcode 11 Beta and converting to Swift 5 I get the following warning:
Implicitly unwrapped property 'residenceId' declared here
Later in the class I also have this function:
func jsonDictionary() -> [String : Any] {
return ["residenceId": residenceId]
}
Here I get the warning
Coercion of implicitly unwrappable value of type 'Int?' to 'Any' does not unwrap optional
Are we no longer allowed to use implicitly unwrapped optional?
EDIT:
After some more looking into it, I have come to believe that "Implicitly unwrapped property 'residenceId' declared here" is not actually a warning, but rather some info (it is in a grey label rather than usual yellow) to help me understand why I am getting the second warning.
And to clarify, my question is if we are no longer able to use the '!' symbol on properties to define an implicitly unwrapped property (obviously only if we are sure it will not be nil) in order to later avoid explicitly unwrapping it (and thus simplifying the code).
Since Swift 4, ImplicitlyUnwrappedOptional or ! as we knew it, became Optional.
Check:
let a: ImplicitlyUnwrappedOptional<Int> = 1
will spit out the error:
'ImplicitlyUnwrappedOptional' has been renamed to 'Optional'
So instead if we do:
let a: Int! = 1
print(type(of: a)) //will print "Optional<Int>"
It's still Optional<Int> but indicates to the compiler that it can be implicitly unwrapped.
Implicit Unwrapping is Part of a Declaration.
...
consider ! to be a synonym for ? with the addition that it adds a flag on the declaration letting the compiler know that the declared value can be implicitly unwrapped.
Ref: Reimplementation of Implicitly Unwrapped Optionals
Now getting to the main question:
If you do:
let a: Int! = 1
let b: Any = a
print(type(of: b)) //prints "Optional<Int>"
It will give the following warning:
Expression implicitly coerced from 'Int?' to 'Any'
or as per Xcode 11
Coercion of implicitly unwrappable value of type 'Int?' to 'Any' does not unwrap optional
Note here that we tried to get a non-optional Any out of an Int? which means we were basically expecting an Int but just by specifying Any it won't also unwrap the Optional.
It will remain an Optional, and this is the meaning behind that warning.
Solutions:
To handle this warning gracefully, we can do any of the following:
let a: Int! = 1
let b: Any? = a
type(of: b) //Optional<Any>.Type
let c: Any! = a
type(of: c) //Optional<Any>.Type
let d: Any = a!
type(of: d) //Int.Type
EDIT: (based on comment)
! instead of ? have any practical difference for the programmer?
! tells the compiler that it can be implicitly unwrapped so it can help ease in the need for optional chaining.
Example:
With ?
class A {
var n: Int? = 1
}
class B {
var a: A? = A()
}
let b: B? = B()
print(b?.a?.n)
/*
but the following won't compile as compiler
will not implicitly unwrap optionals
print(b.a.n)
*/
With !
class A {
var n: Int! = 1
}
class B {
var a: A! = A()
}
let b: B! = B()
print(b.a.n) //compiler will implicitly unwrap `!` similar to print(b!.a!.n)
//also... you can still safely unwrap if you want
print(b?.a?.n)
b.a.n and b?.a?.n will both give an Optional<Int> at the end
Ofcourse if b or a is nil then b.a.n will crash because it's implicitly unwrapping b and a to get to n which is Optional<Int>
To get Int instead of Optional<Int>, you would do b.a.n! and so in your case you would do: print(residenceId!) to get Int
I hope I made sense

Convert String to int in Swift 3

I have the following variable:
var npill : String!
It's an Int value, but I can't set it as Int because of:
npillIn: fieldNumeroPillole.text!,
How can I convert this var to a Int var? I have tried the following:
var number1: Int = (npill! as NSString).intValue
By the above code I receive the following error:
cannot use instance member 'npill' within property initializer, property initializers run before "self" is aviable
If I then set:
var number1: Int = (self.npill! as NSString).intValue
The error it outputs is as follows:
Value of type '(NSObject) -> () -> Farmaco' has no member 'npill'
If anyone knows how I should be converting it properly, please let me know.
Update
Thank you to #Hamish for pointing out what the OP was asking
So the problem seems to be this
import Foundation
class Foo {
var npill : String!
var number1: Int = (npill! as NSString).intValue
}
error: cannot use instance member 'npill' within property initializer; property initializers run before 'self' is available
var number1: Int = (npill! as NSString).intValue
^
What's going on here?
You are using a property to populate another property, and this is not allowed.
Solution
However you can easily fix the problem postponing the initialisation of number1. Infact if you make number1 lazy, it will be populated only when used.
class Foo {
var npill : String!
lazy var number1: Int = { return Int(self.npill!)! }()
}
Warning: Of course this code will crash if npill is still nil when number1 is used.
Old version
You can simply write
let npill: String! = "34"
if let npill = npill, let num = Int(npill) {
print(num) // <-- here you have your Int
}
(As #Hamish pointed out in a comment below, I misunderstood what the OP was really asking about. I'll leave my answer, however, as some curiosa and insights regarding ! type annotation, which may be relevant for future readers of this question)
For any type of String optionals, their values needs to be unwrapped prior to using the failable init?(_ text: String) initializer or Int.
In your example, the variable npill is an optional, as you've annotated its type with the ! specifier (which should be used with care). Quoting from the implemented evolution proposal SE-0054 [emphasis mine]
Appending ! to the type of a Swift declaration will give it optional
type and annotate the declaration with an attribute stating that it
may be implicitly unwrapped when used.
Hence, it's entirely legal to use npill directly with the init?(_ text: String) initializer of Int, as it will be unwrapped (without any safety check for nil content!) on-the-fly upon use.
// UNSAFE example!
var npill: String! = "42"
if let npillInt = Int(npill) {
/* ^^^^^^^^ ^^^^^- since 'npill' has a type annotated with
| '!', it will be unsafely unwrapped at
| this point
\
the optional binding here safely unwraps the return from
the failable Int initializer, but has nothing to do with
the unwrapping of 'npill' */
print(npillInt) // 42
}
// why unsafe? consider
npill = nil
if let npillInt = Int(npill) { // runtime exception!
// ...
}
Generally you should avoid using the ! annotation, however, unless you are entirely certain that the content of the resulting optional variable will never ever be nil.
Leaving aside the cons of even using the ! annotation: you may implement a safe version of the unsafe example above, by overriding the unsafe implicit unwrapping with safe explicit unwrapping techniques. For a given optional variable declared using the ! annotation, we may still apply safe means to unwrap it, e.g. optional binding or using the nil coalescing operator. #appzYourLife has already showed one perfectly valid and safe way to handle the unwrapping and attempted type conversion of npill using optional binding, so I'll simply include another example using the nil coalescing operator instead:
// "safe" example (STILL: why use the `!` annotation?)
var npill: String! = "42"
if let npillInt = Int(npill ?? "x") {
/* ^^^^^ if 'npill' is 'nil', the Int initializer will
be given the value "x", which itself will lead
it to fail, which is safe here as we intend to
bind the result of the initialization to 'npillInt' */
print(npillInt) // 42
}
npill = nil
if let npillInt = Int(npill ?? "x") {
// ... doesnt enter
}
The consensus of the examples above is that if we're even slightly uncertain whether npill can ever be nil or not, we need to treat it as if it was just an optional not type annotated with ! (i.e. String?); overriding the default unsafe unwrapping with safe means when working with the variable. In such a case, why would we even want to use the ! typ annotation at all, as it only brings fragility/danger to our application?

Why does Optional Binding evaluate to type Bool?

Why is this variable i not substituted for Bool but optional binding is?
Swift claims this in the guide..
Swift’s type safety prevents non-Boolean values from being substituted
for Bool. The following example reports a compile-time error:
let i = 1
if i {
// this example will not compile, and will report an error
}
Yet this compiles
var foo: String?
if let bar = foo {
print("Non nil")
}
An optional is essentially an enum with two possible values either a designated value, in your example a string, or nil. An if let binding is not being substituted for a Bool in your example. Instead, it is checking if the variable foo is nil and if it is not nil then it sets bar equal to foo and performs the code inside the block. An if let binding is thus essentially a shortcut for
var foo: String?
if foo != nil {
//Set bar equal to the unwrapped value of foo
let bar = foo!
//Do whatever
}
The efficiency of this is best shown in a case where you would want to check if something is nil and check some characteristic of the value if it is not nil. Say you wanted to also check that foo has more than 5 characters and if it does then do something. Since foo could be nil you would have to check for it specifically to ensure it is not. An if let binding will let you do this:
if let bar = foo where bar.characters.count > 5 {
print(bar)
}
rather than this:
if foo != nil && foo?.characters.count > 5 {
let bar = foo!
print(bar)
}
It basically makes very readable, and thus more maintainable code. Also, it prevents you from having to unwrap the optional manually (the ! operator at the end of foo).

Optional binding to an immutable explicitly declared to be of type 'ImplicitlyUnwrappedOptional<T>' yields an immutable of type 'Optional<T>'

Background
When I was explaining the logical error in the following question:
How to use guard statement to detect nil after an assignment?
I stumbled over a peculiarity that I cannot explain myself.
Details and question
As shown in the thread above, we can explicitly state the type of the scope-local immutable, say b, in if let b = rhs ... and guard let b = rhs ... else clauses to be of the same optional type as the rhs value to (attempted to be assigned) to b, in which case the "optional binding" will always succeed:
let a: Int?
// ...
if let b: Int? = a { // will always succeed, 'Int?' to 'Int?'
print(b.dynamicType) // Optional<Int>
}
We could discuss whether this should even be allowed, as this is in essence a bloated block-local assignment, but this is not the point of this question. Rather, explaining the following peculiarity:
If we explicitly declare b above to be of an implicitly unwrapped optional type (here: Int!), then b in the scope of the if let clause is, for some reason, just a regular non-unwrapped optional, namely Int.
let a: Int? = nil
if let b: Int! = a {
print(b.dynamicType) // Optional<Int>
/* why not ImplicitlyUnwrappedOptional<Int> ? */
}
Question:
Why is b above—declared to be an implicitly unwrapped optional (Int!)—converted to a "regular" optional (Int?) (in the if let clause)?
Investigations of my own
I've simply noted that the above "shadow conversion" is naturally not present for regular assignments of optionals to implicitly unwrapped optionals
let c: Int? = 10
let d: Int! = c
print(f.dynamicType) // ImplicitlyUnwrappedOptional<Int>
neither present if we use an always-succeeding if let block-local assignment from non-optional (Int) to implicitly unwrapped optional (Int!)
let c = 10
if let d: Int! = c {
print(d.dynamicType) // ImplicitlyUnwrappedOptional<Int>
}
After feedback from #Sulthan in the comments below, we see that this "shadow conversion" is not present if a above is a double optional (Int??), e.g.
let a: Int?? = 10
if let b: Int! = a {
print(b.dynamicType) // ImplicitlyUnwrappedOptional<Int>
}
if let b: Int? = a {
print(b.dynamicType) // Optional<Int>
}
I am using Swift 2.2 / Xcode 7.3.

why there need add '!' in code suffix

enum Season: Int {
case Spring = 0
case Summer = 1
case Autumn = 2
case Winter = 3
}
var SeasonTime1 = Season.Spring
//why ? this code suffix need add !
SeasonTime1 = Season.init(rawValue: 2)!
List item
// why? there don't need add !
var SeasonTime2 = Season.init(rawValue: 2)
This is because Enum uses a failable initializer (see documentation here). As its title implies, a failable initilizer can fail and return nil. Objects that can contain nil are Optionals in Swift. Therefore you could have:
let seasonTime1 = Season.init(rawValue: 2)
In which case the type of seasonTime1 is Optional<Season>. When you want to use the value, you then have to unwrap the Optional, either using if let, guard or !. In this case:
let seasonTime1 = Season.init(rawValue: 2)!
You're unwrapping it immediately, so the type of seasonTime1 will be Season. Note the following code:
let seasonTime1 = Season.init(rawValue: 2222)!
This will run, but if you access seasonTime1 it will fail. This is because there is no enum with a raw value of 2222, and so seasonTime1 will contain nil. Since it is implicitly unwrapped, the fact that it contains nil is illegal, which will cause a crash if the unwrapping occurs.
Because the compiler cannot infer that the raw value type exists so you need the '!' too force unwrap it. If you wrap it in a guard statement you can ensure that it is of the type that "you" know it is. Then you don't need the '!'