Why use force unwrapping in this example? - swift

let john = Person()
john.residence = Residence()
let johnsAddress = Address()
johnsAddress.buildingName = "The Larches"
johnsAddress.street = "Laurel Street"
john.residence!.address = johnsAddress
The above example is in Apple Language Guide.
Why did you use force unwrapping (exclamation mark) in the last line?
Is there a difference between ! and ? in this example?

A forced unwrapping is used when it's know that the optional has a non nil value. Using it on an optional with nil value generates a runtime exception.
The normal unwrapping instead is conditional. If john.residence is nil, then whatever is after it is ignored, and no error is generated (see Optional Chaining). The statement simply doesn't do anything, hence no assignment takes place.
The reason why the forced unwrapping exists is that it avoids checking for nils when it's known it has a value. For instance let's suppose you want to print to the console the content of a String variable:
let x: String?
print("\(x)")
If you initialize the variable instead, it will print something you wouldn't probably expect:
let x: String? = "Test"
print("\(x)") // Prints "Optional("Test")"
That happens because x is an Optional and not a String type.
To fix that, you force the unwrapping using the exclamation mark:
print("\(x!)") // Prints "Test"

Related

Unexpectedly found nil while unwrapping an Optional value but value exist

I know I need to bind my varaible for unwrap but the problem is my value is not reconized but present.
This is my code :
surveyW.karmaWin = Int(endedSurvey["karma"].string!)
endedSurvey is a array dictionary of my JSON backend. I get a Unexpectedly found nil while unwrapping an Optional value error.
I specify that I force the unwrapping to show you my problem.
The problem is my array contains the karma value. I show you the screen of the value:
So we can see that the value existing. Why I get a Unexpectedly found nil...?
The value contained in "karma" is not String. You're trying to force cast it with SwiftyJSON but it tells you it has a nil. You first need to extract value as it is - .int, and after that convert that to something else if needed.
surveyW.karmaWin = endedSurvey["karma"].int
You can use intValue because SwiftyJSON has two kinds of "getters" for retrieving values: Optional and non-Optional
.string and .int are the optional getters for the String and Int representation of a value, so you have to unwrap it before use
if let fbId = fbJson["id"].string {
print(fbId)
}
If you are 100% sure that there will always be a value, you can use the equivalent of "force unwrap" by using the non-Optional getter and you don't need if let anymore:
let fbId = fbJson["id"].stringValue
In your code :
surveyW.karmaWin = endedSurvey["karma"].intValue
endedSurvey["karma"] is an Integer not string and also good way to unwrap an optional is:
if let karma = endedSurvey["karma"] as? Int{
surveyW.karmaWin = karma
}

Why don't you need to unwrap an optional type value when being set?

Does it mean that the set operation doesn't read the actual value of the Optional, so it doesn't need to be unwrapped?
var str = "Hello, playground"
class Base{
var name:String?
};
var obj = Base()
obj.name = "hello" //this line don't need unwrapping first
An optional is a box. The box can either contain nothing (which is called nil) or it can contain something of a specific type (a String in your example). You unwrap an optional to access the value inside in the box.
When you are assigning a value to an optional, you just need to assign the value to the box itself. There is no need to unwrap anything, because you are just putting a value into the box. Swift either empties the box, if you assign nil, or it wraps the value by putting it into the box.
Unwrapping is for accessing a value that is already in the box.
Answering your question from a comment on another answer...
But why Optional binding don't need unwrapping? i think i if let constantName = some Optional is kind of assignment too
Optional binding is an unwrapping operation and an assignment operation. It says "if there is a value inside the box, assign it to this new variable and enter the then clause, otherwise proceed to the else clause if it exists".
var optionalValue: String? = "hello"
if let value = optionalValue {
// value is the contents of the box, it has type String
print("value is \(value)")
} else {
// the optional binding failed because the box is empty
print("optionalValue is nil")
}
When you set an Optional property, you do not have to unwrap it.
Unwrapping is required only when assigning an optional value to a non-optional property:
var name: String = "" // non-optional
var str: String?
// this will not compile, because you need to unwrap str first
name = str
// this will compile, because we're providing a default value
name = str ?? ""
// this will also compile, because name is not an optional
// it would still compile if name was optional, because str is optional too
str = name

optional unwrapping nil not always fatal error

Why does this piece of code give me an Fatal Error
var number: Int? = .none
print(number!)
Fatal error: Unexpectedly found nil while unwrapping an Optional value
But this piece of code does not?
var number: Int! = .none
print(number)
nil
Doesn't Int! automatically unwrap the variable on use? Why doesn't it throw a fatal error when number gets printed?
An Optional is a type that can hold or not a wrapped value.
In the first case, you're telling inside the code that numbers contains an Int variable (this is because of numbers!), which is a very unsafe way to work with Optionals. When you unwrap numbers, it has to contain a value or, on the contrary, has to not be nil. Since the compiler actually finds that there isn't an Int value but nil, so it calls fatal error.
In the second case, instead, you're simply printing an Optional, that can hold or not an Int value. In this specific case, it does not hold an Int value, so nil will be printed.
Here you can find more on Optionals:
https://developer.apple.com/documentation/swift/optional
Implicitly unwrapped optionals are still optionals under the hood; they just get automatically unwrapped as needed.
However, the print function accepts optional values, so unwrapping it there isn't needed. In the first case you get an error because you're explicitly unwrapping it, but in the second it's happy to keep it wrapped so there's no error. It'll work like that with other functions that accept optionals as well, but if you use it somewhere that an optional does not work, then it forces an unwrap and the behavior becomes the same for both:
let num1: Int! = nil
let num2: Int? = nil
print(String(describing: num1)) // works fine
print(String(describing: num2!)) // error
print(num1 + 1) // error
print(num2! + 1) // also error

Difference between optional and forced unwrapping [duplicate]

This question already has answers here:
What is an optional value in Swift?
(15 answers)
Closed 5 years ago.
Below is the code for optional string for variable name yourname and yourname2.
Practically what is difference between them and how forced unwrapping in case of yourname2
var yourname:String?
yourname = "Paula"
if yourname != nil {
println("Your name is \(yourname)")
}
var yourname2:String!
yourname2 = "John"
if yourname2 != nil {
println("Your name is \(yourname2!)")
}
The String? is normal optional. It can contain either String or nil.
The String! is an implicitly unwrapped optional where you indicate that it will always have a value - after it is initialized.
yourname in your case is an optional, yourname2! isn't.
Your first print statement will output something like "Your name is Optional("Paula")"
Your second print statement will output something like "Your name is John". It will print the same if you remove the exclamation mark from the statement.
By the way, Swift documentation is available as "The Swift Programming Language" for free on iBooks and the very latest is also online here.
What you call 'forced unwrapping' is known as an 'implicitly unwrapped optional'. An implicitly unwrapped optional is normally used in objects that can't or won't assign a value to a property during initialization, but can be expected to always return a non-nil value when used. Using an implicitly unwrapped optional reduces code safety since its value can't be checked before runtime, but allows you to skip unwrapping a property every time it's used. For instance:
var a: Int!
var b: Int?
var c = a + b //won't compile
var d = a + b! //will compile, but will throw an error during runtime
var e = a + a //will compile, but will throw an error during runtime
a = 1
b = 2
var f = a + b //still won't compile
var g = a + b! //will compile, won't throw an error
var h = a + a //will compile, won't throw an error
Generally speaking you should always use optionals if you don't assign a value to a variable at initialization. It will reduce program crashes due to programmer mistakes and make your code safer.
Forced unwrapping an optional, give the message to the compiler that you are sure that the optional will not be nil. But If it will be nil, then it throws the error:
fatal error: unexpectedly found nil while unwrapping an Optional value.
The better approach to unwrap an optional is by optional binding. if-let statement is used for optional binding : First the optional is assign to a arbitrary constant of non-optional type. The assignment is only valid and works if optional has a value. If the optional is nil, then this can be proceed with an else clause.

It it okay to access an optional variable with question mark without exclamation mark?

I know that an optional constant or variable with a question mark needs an exclamation mark to access its value. then, I tried to exam it with the following code.
var aaa:String? = "3"
println("aaa = \(aaa!)")
Yes. It was okay. It printed "3" on Console Output. and next exam I tried like that
var aaa:String? = "3"
println("aaa = \(aaa)")
It also printed "3" without any error message. It worked well.
I learned about Forced Unwrapping that en exclamation mark is needed to access to a value of Optional. But, I could access it without the mark. Is it right? I wonder what is wrong. Am I misunderstanding Optional?
You are correctly understanding Optionals and Forced Unwrapping. The reason that you can print the optional variable is that the type Optional can also be printed. If you print an Optional instead of the real value, it will either print the value if it has one, or "nil" if it doesn't.
Also, just in case you don't realize it. Forced Unwrapping will cause the whole program to crash if the optional is nil at the time. To be safer, you should use Optional Binding:
var aaa: String? = "3"
if let actualString = aaa {
// actualString becomes a non-optional version of aaa
// if aaa were nil, this block would not be run at all
println(actualString)
}
Also, some extra information about the printing of instances. Printing uses the protocol Printable which defines a description property. Anything that implements this protocol can customize the way they print out. Optional has its own implementation of this protocol which is how it decides to either print "nil" or the description of the actual value.
Println() will print the value if it has any otherwise it will print nil. Just to understand things better just try to assign value of aaa to another string variable. It will throw error that value of optional type not unwrapped.
var aString:NSString? = "Hello"
var bString = aString // Compiler allows, as you are assigning to optional type again.
var cString:NSString = aString // Compiler throws error. You cannot assign optional type without unwrapping.
So to answer your question you need to use ! to get the value.
Edit:
var foo:Bool?
foo = false
if foo { // This always evaluates to `True`
...
}
if foo! { // This condition will now fail
...
}
The reason foo evaluated to True is because it was not unwrapped. Since its not unwrapped its just checking whether it has a value or not(true or false does not matter).
When foo was unwrapped it returned a value False hence the second if condition failed.
The println function is a special case. It automatically unwraps the variable for you. If the variable were nil, it would print nil. In other contexts, you do need to unwrap the variable yourself.