In swift you can unwrap optional values with a guard statement
guard let foo = foo else { return nil }
Is this statement making a copy of foo? In other words, could this statement be potentially expensive if foo is very large?
Actually this depends on type of foo e.x class type won't create a copy unlike struct type
guard isn't a magic keyword it simply if not presented in 1 word
guard let foo = foo else { return nil }
Could this statement be potentially expensive if foo is very large?
Instead of asking yourself the question that way, ask it this way: what if you had said
if foo != nil {
let foo = foo!
// everything else here
}
Was saying foo! to unwrap the Optional "expensive"? Whatever your answer is, it must be exactly the same for guard let foo = foo, because they both do exactly the same thing: they test for nil and, if safe, they unwrap the Optional. And that is all they both do. The one is merely syntactic sugar for the other.
You have two ways:
1- To only check if this foo does not equal nil
In this case you can check if foo is nil or not
if foo != nil {
// do you work here
}
2- To get information from foo
In this case, you have to unwrap this optional (with guard-let or if-let statements) and here we have two cases:
- if foo is a class, then it’s a reference type. so there will be no copy and a reference to this instance is created
- if foo is a struct, then it’s a value type. so an entirely new instance is created (copied from the original)
Also you can read this answer to see should you choose struct or class in swift
If the property you're unwrapping is a reference type (e.g. a class) then no it will not make a copy, it will just create a new property with a reference to the original instance.
If the property you're unwrapping is a value type (e.g. struct) then it will make a copy.
Related
This question already has answers here:
Swift variable decorations with "?" (question mark) and "!" (exclamation mark)
(1 answer)
What is the difference between String? and String! (two ways of creating an optional variable)?
(7 answers)
Closed 4 years ago.
I noticed that some coding examples for Swift declare optional properties in different ways. However, I seem to have trouble trying to tell them apart (or, rather, when to use each.)
class MyClass {
// I believe this can start as nil but should always be set
// once it is.
var optionalProperty1: Type!
// I believe this can be set or nil anytime.
var optionalProperty2: Type?
// I think this is the same as
// var optionalProperty3: Type!
lazy var optionalProperty3: Type
}
How does each one differ from the others and when should each one be used?
var optionalProperty1: Type!
When you're sure you will have value for this property such as timestamp it will be something for sure. And Yes it can be nil too.
var optionalProperty2: Type?
When you're not sure about the value (Or this field is not mandatory) take it as optional for example:- If I make a Person class address can be optional and name will not.
lazy var optionalProperty3: Type
This syntax is wrong you can not declare lazy property in this way. You must assign something to it initially. See below example:
/// First way
lazy var optionalProperty3: String = {
return "Hello"
}()
/// Second way
lazy var optionalProperty4 = "Hello"
A lazy stored property is a property whose initial value is not calculated until the first time it is used. You indicate a lazy stored property by writing the lazy modifier before its declaration. lazy variables are great for things that need to be setup once, then never re-set.
One more thing you really don't need to specify type in modern Swift. Means if you will assign 0 it will be an integer itself, if you will assign 0.0 it will take it as double and same for String, Array etc.
The third declaration is not an optional.
The third one declares a lazy property. Lazy properties will only be initialised when they are first used. Example:
class A {
lazy var a: Int = {
print("hello")
return 1 + 1
}()
}
let a = A()
print(a.a)
If you remove the last line, hello will not be printed.
The first declaration is a implicitly unwrapped optional while the second declaration is a normal optional.
When you access members of a normal optional, you need to unwrap it with ? or !:
var myInt: Int? = ...
print(myInt.description) // doesn't compile, must unwrap
print(myInt!.description) // will crash if myInt is nil
print(myInt?.description) // will print "nil" if myInt is nil
On the other hand, implicitly unwrapped optionals do this implicitly - whenever you try to access a member, it will implicitly unwrap it with ! for you:
var myInt: Int! = ...
print(myInt.description) // equivalent to "myInt!.description"
From Apple's Swift documentation:
Optionals (?): "You use optionals in situations where a value may be absent. An optional represents two possibilities: Either there is a value, and you can unwrap the optional to access that value, or there isn’t a value at all."
Implicitly Unwrapped Optionals (!): "As described above, optionals indicate that a constant or variable is allowed to have “no value”. Optionals can be checked with an if statement to see if a value exists, and can be conditionally unwrapped with optional binding to access the optional’s value if it does exist.
Sometimes it’s clear from a program’s structure that an optional will always have a value, after that value is first set. In these cases, it’s useful to remove the need to check and unwrap the optional’s value every time it’s accessed, because it can be safely assumed to have a value all of the time.
These kinds of optionals are defined as implicitly unwrapped optionals. You write an implicitly unwrapped optional by placing an exclamation mark (String!) rather than a question mark (String?) after the type that you want to make optional.
Implicitly unwrapped optionals are useful when an optional’s value is confirmed to exist immediately after the optional is first defined and can definitely be assumed to exist at every point thereafter. The primary use of implicitly unwrapped optionals in Swift is during class initialization, as described in Unowned References and Implicitly Unwrapped Optional Properties."
Read more at https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TheBasics.html
Explicitly Unwrapped Variable
var optionalProperty1: Type!
This means that the value should never be nil. It will always be initialized but it is better to use var optionalProperty1: Type
Optional
var optionalProperty2: Type?
This is an optional value, meaning that it can either have a value or be nil. normally to use the value you would need to unwrap it. using either conditional unwrapping or a guard statement...
if let value = optionalProperty2 {
print("optionalProperty2 had a value, value is set")
}
guard let value = optionalProperty2 else {
print("optionalProperty2 was nil value is nil")
}
or you can just check if it has a value and explicitly unwrap it (which is not considered best practice)
if optionalProperty2 != nil {
print("optionalProperty2 is set to \(optionalProperty2!)")
}
Lazy Variable
lazy var optionalProperty3: Type a lazy variable is different, it is not an optional unless you define it to be optional. Lazy variables do not initialise to a value until the value is first used. So if you do not call/use the variable it will never be set.
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 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).
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]
The name of the ! always confuses me: it's called an 'implicitly unwrapped optional'. However, what is implicit about it? Implicit means "implied though not plainly expressed." However, does not adding a ! plainly express its purpose? Does not adding a ! make it explicit what we are trying to accomplish?
In Swift, trailing exclamation marks (!) are used in two different ways. One is called Forced Unwrapping. This is when you have a variable defined as an Optional and you want to basically assert that the value is not nil so that you can use it as if it were not an optional:
var optionalName: String? = "World"
if optionalName != nil {
sayHelloTo(optionalString!)
}
An alternate way you could describe "Forced Unwrapping" is "Explicit Unwrapping", but forced adds the extra hint that the whole program will crash if you try to "Force Unwrap" an optional that is nil.
The second is when you are actually declaring the type of a variable and it is called an Implicitly Unwrapped Optional. This is for when you want to declare a variable that is technically optional, but that you will treat as if it is not optional. Every time you use this Implicitly Unwrapped Optional, it is in reality, doing the "Force Unwrapping" I described above:
var name: String! = "World"
if name != nil {
sayHelloTo(name)
}
You can still test an Implicitly Unwrapped Optional for nil, but you can also use it directly as if it were not optional. That is why it is considered implicit. Every time you use it, it is automatically, implicitly unwrapped for you.
Like "Forced Unwrapping" an "Implicitly Unwrapped Optional" will still crash the entire program if you try to use it when it is nil
Normal Optional
var foo : Foo? = Foo()
foo!.doSomething() // explicitly unwrap it and call the method
Implicitly Unwrapped Optional
var foo : Foo! = Foo()
foo.doSomething() // implicitly unwrap it and call the method just like it is not optional
In both case, you need something to declare an optional (? or !). Implicitly Unwrapped Optional does not add more. But you can omit unwrap operator when use it.