Using ? (optionals) in Swift variables [duplicate] - ios

This question already has answers here:
What is an optional value in Swift?
(15 answers)
Closed 8 years ago.
What exactly is the difference between a property definition in Swift of:
var window: UIWindow?
vs
var window: UIWindow
I've read it's basically an "optional" but I don't understand what it's for.
This is creating a class property called window right? so what's the need for the '?'

The ? identifier means that the variable is optional, meaning its value can be nil. If you have a value in your code, declaring it as non-optional allows the compiler to check at build time if it has a chance to become nil.
You can check whether it is nil in an if statement:
var optionalName: String? = "John Appleseed"
if optionalName {
// <-- here we know it's not nil, for sure!
}
Many methods that require a parameter to be non-nil will declare that they explicitly need a non-optional value. If you have an optional value, you can convert it into non-optional (for example, UIWindow? -> UIWindow) by unwrapping it. One of the primary methods for unwrapping is an if let statement:
var greeting = "Hello!"
// at this point in the code, optionalName could be nil
if let name = optionalName {
// here, we've unwrapped it into name, which is not optional and can't be nil
greeting = "Hello, \(name)"
}
See The Swift Programming Language, page 11 for a brief introduction, or page 46 for a more detailed description.

UIWindow? means that the value may be absent. It's either an UIWindow instance or nothing.

Related

Why optional chaining is required in the following case if the variable type is not declare explicitly? [duplicate]

This question already has answers here:
Why does captured object reference to implicitly unwrapped variable have to be unwrapped? [duplicate]
(1 answer)
Implicitly unwrapped optional assign in Xcode 8
(1 answer)
Closed 1 year ago.
I have the following extension
extension UIWindow {
static var key: UIWindow! {
if #available(iOS 13, *) {
return UIApplication.shared.windows.first { $0.isKeyWindow }
} else {
return UIApplication.shared.keyWindow
}
}
}
I can use it without optional chaining in the following case
Case 1
UIWindow.key.addGestureRecognizer(UIGestureRecognizer())
Case 2
let key: UIWindow = UIWindow.key
key.addGestureRecognizer(UIGestureRecognizer())
But, when use it in the following case, I will get a compiler error
Case 3 (Not working)
let key = UIWindow.key
// value of optional type 'UIWindow?' must be unwrapped to refer to member 'addGestureRecognizer' of wrapped base type 'UIWindow'
key.addGestureRecognizer(UIGestureRecognizer())
May I know why it is so? Why the compiler cannot recognise key as UIWindow, without having programmer to declare its type explicitly?
This behaviour is introduced in SE-054: Abolish ImplicitlyUnwrappedOptional type. The point is to limit the use of implicitly unwrapped optionals.
As the proposal describes:
If the expression can be explicitly type checked with a strong optional type, it will be.
So the "explicitly" unwrapped optional is always preferred, when no other information is provided. The key in let key = UIWindow.key is of type UIWindow?.
It's only when you, e.g. provide an explicit type annotation : UIWindow, that the right hand side being of type UIWindow? won't typecheck anymore, and so the compiler has to implicitly unwrap the UIWindow!.
The rationale is:
This model is more predictable because it prevents IUOs from propagating implicitly through the codebase, and converts them to strong optionals, the safer option, by default.

conditional binding must have Optional type, not 'String' [duplicate]

This question already has answers here:
Conditional Binding: if let error – Initializer for conditional binding must have Optional type
(8 answers)
Closed 3 years ago.
I understand that The text property of UILabel is optional, I tried adding an else but i'm not sure what else to add.
productData.product.productName is me getting the name of the product from the database
if var pName = productData.product.productName { //error
self.productName.text = pName
}
#IBOutlet weak var pName: UILabel!
Initializer for conditional binding must have Optional type, not 'String' is the error I get, It was working I think im not sure where its gone wrong
It states that the use of if condition is unnecessary, because the 'productName' is not optional.
You can directly add the value to your label.
self.productName.text = productData.product.productName //Product name is not optional
Optional chaining is used when you try to get a optional value.
For example, if you want to get the text of label then you'll require if condition.
if var text = self.productName.text { //Text in label is optional
print(text)
}
It seems like the compiler is complaining that productData.product.productName is NOT an Optional. The if var name = ____ construct only works on Optionals.
If you are testing for a non-empty String, you may want to check the count or isEmpty instead.

How to use optional "?" and "!" in swift? [duplicate]

This question already has answers here:
What does "Fatal error: Unexpectedly found nil while unwrapping an Optional value" mean?
(16 answers)
Closed 6 years ago.
I am studying XCode7.3. The "?" and "!" always make me confused.
I have code like below.
The lines name : name, type : type and image : image displaying error message :
Value of optional type 'String?' not unwrapped, did you mean to use '!' or '?'?
#IBAction func unwindToHomeScreen( segue : UIStoryboardSegue ) {
if let addRestaurantController = segue.sourceViewController as? AddRestaurantController {
let name = addRestaurantController.name
let location = addRestaurantController.location
let type = addRestaurantController.type
let isVisited = addRestaurantController.isVisited
let image = addRestaurantController.imageView
restaurants.append( Restaurant(
name : name,
type : type,
location : location,
phoneNumber : "UNKNOW",
image : image,
isVisited : isVisited? ?? false
) )
print( addRestaurantController.imageView )
}
}
I modify code to name : name! or name : name?, it still doesn't work. How can I fix it?
I think this will solve your problem.
If addRestaurantController.location, addRestaurantController.name and addRestaurantController.type are optional.
#IBAction func unwindToHomeScreen( segue : UIStoryboardSegue ) {
if let addRestaurantController = segue.sourceViewController as? AddRestaurantController , name = addRestaurantController.name, location = addRestaurantController.location, type = addRestaurantController.type, isVisited = addRestaurantController.isVisited, image = addRestaurantController.imageView
{
restaurants.append( Restaurant(
name : name,
type : type,
location : location,
phoneNumber : "UNKNOW",
image : image,
isVisited : isVisited? ?? false
) )
}
}
You haven't specify that whether addRestaurantController.location, addRestaurantController.name and addRestaurantController.type are optional or not. And you randomly submitted your question without even analysing it properly.
Please give more value to other people's time. And ask meaningful questions. Read more about guidelines for a Stackoverflow question.
There might be few reasons, but first I'd suggest you to read about optionals (?) and explicitly unwrapped optionals (!) here https://itunes.apple.com/us/book/swift-programming-language/id881256329?mt=11
As far as the problem, it is most likely that optionality of variable name in Restaurant is defined differently comparing to local definition. While locally variable name is defined to be optional, e.g. let name: String?, Restaurant expects it to be non optional (probably it defined as let name: String (note no ? at the end)). That mean that you need to unwrap optional value to pass it to the Restaurant (please see the link above for ways of unwrapping, there are few depending on your use-case)
If you are switching to Swift 3, keep in mind that behavior of explicitly unwrapped optionals changed. For motivation and in depth description, please read this proposal https://github.com/apple/swift-evolution/blob/master/proposals/0054-abolish-iuo.md
But as it's been pointed out, Swift 3 can not be compiled in Xcode 7, you need to download beta of Xcode 8 for that

var definitions in swift [duplicate]

In The Swift Programming Language (book of Apple) I've read that you can create optional variables in 2 ways: using a question mark (?) or by using an exclamation mark (!).
The difference is that when you get the value of an optional with (?) you have to use an exclamation mark every time you want the value:
var str: String? = "Question mark?"
println(str!) // Exclamation mark needed
str = nil
While with an (!) you can get it without a suffix:
var str: String! = "Exclamation mark!"
println(str) // No suffix needed
str = nil
What is the difference and why are there 2 ways if there is no difference at all?
The real benefit to using implicitly unwrapped optionals (declared with the !) is related to class initialisation when two classes point to each other and you need to avoid a strong-reference cycle. For example:
Class A <-> Class B
Class A's init routine needs to create (and own) class B, and B needs a weak reference back to A:
class A {
let instanceOfB: B!
init() {
self.instanceOfB = B(instanceOfA: self)
}
}
class B {
unowned let instanceOfA: A
init(instanceOfA: A) {
self.instanceOfA = instanceOfA
}
}
Now,
Class B needs a reference to class A to be initialised.
Class A can only pass self to class B's initialiser once it's fully initialised.
For Class A to be considered as initialised before Class B is created, the property instanceOfB must therefore be optional.
However, once A's been created it would be annoying to have to access instanceOfB using instanceOfB! since we know that there has to be a B
To avoid this, instanceOfB is declared as an implicity unwrapped optional (instanceOfB!), and we can access it using just instanceOfB. (Furthermore, I suspect that the compiler can optimise the access differently too).
An example of this is given on pages 464 to 466 of the book.
Summary:
Use ? if the value can become nil in the future, so that you test for this.
Use ! if it really shouldn't become nil in the future, but it needs to be nil initially.
You should go beyond the syntactic sugar.
There are two completely different polymorphic types. The syntactic sugar just uses either one or the other of these types.
When you write Foo? as a type you really have Optional<Foo>, while when you write Foo! you really have ImplicitlyUnwrappedOptional<Foo>.
These are two different types, and they are different from Foo as well.
The values you create with ? are plain optional values as you mentioned, you should access it via optional binding (if let unwrappedValue = myOptionalValue) or by using the exclamation point syntax myOptionalValue!.doSomething().
The values you create with ! are called implicitly unwrapped optionals. With them, you don't need to manually unwrap before using them. When you do val myOptionalValue!.doSomething().
The value will be automatically unwrapped for you when you use myOptionalValue directly, be careful with this though, because accessing an implicitly unwrapped value when there is actually no value in it (when it is nil) will result in a runtime error.
? (Optional) indicates your variable may contain a nil value while ! (unwrapper) indicates your variable must have a memory (or value) when it is used (tried to get a value from it) at runtime.
The main difference is that optional chaining fails gracefully when the optional is nil, whereas forced unwrapping triggers a runtime error when the optional is nil.
To reflect the fact that optional chaining can be called on a nil value, the result of an optional chaining call is always an optional value, even if the property, method, or subscript you are querying returns a nonoptional value. You can use this optional return value to check whether the optional chaining call was successful (the returned optional contains a value), or did not succeed due to a nil value in the chain (the returned optional value is nil).
Specifically, the result of an optional chaining call is of the same type as the expected return value, but wrapped in an optional. A property that normally returns an Int will return an Int? when accessed through optional chaining.
var defaultNil : String? // declared variable with default nil value
println(defaultNil) >> nil
var canBeNil : String? = "test"
println(canBeNil) >> optional(test)
canBeNil = nil
println(canBeNil) >> nil
println(canBeNil!) >> // Here nil optional variable is being unwrapped using ! mark (symbol), that will show runtime error. Because a nil optional is being tried to get value using unwrapper
var canNotBeNil : String! = "test"
print(canNotBeNil) >> "test"
var cantBeNil : String = "test"
cantBeNil = nil // can't do this as it's not optional and show a compile time error
For more detail, refer a document by Apple Developer Commitee, in detail
The String! kind is called an implicitly unwrapped optional:
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.
in the optional chaining section you find the answer:
example class:
class Person {
var residence: Residence?
}
class Residence {
var numberOfRooms = 1
}
If you try to access the numberOfRooms property of this person’s residence, by placing an exclamation mark after residence to force the unwrapping of its value, you trigger a runtime error, because there is no residence value to unwrap:
let roomCount = john.residence!.numberOfRooms
// this triggers a runtime error
The code above succeeds when john.residence has a non-nil value and will set roomCount to an Int value containing the appropriate number of rooms. However, this code always triggers a runtime error when residence is nil, as illustrated above.
Optional chaining provides an alternative way to access the value of numberOfRooms. To use optional chaining, use a question mark in place of the exclamation mark:
if let roomCount = john.residence?.numberOfRooms {
println("John's residence has \(roomCount) room(s).")
} else {
println("Unable to retrieve the number of rooms.")
}
// prints "Unable to retrieve the number of rooms."
Well mentioned by #tarmes above. Noticed another usage of implicit optional:
Lets say I have an optional Int:
let firstInt: Int? = 9
And I'm trying to use optional pattern matching and use this optional Int like this:
if case let myFirstInt? = firstInt where myFirstInt > 1 {
print("Valid")
} else {
print("Invalid")
}
Notice that I'm using implicit optional with local parameter myFirstInt making it safe for nil condition linked with optional firstInt. If now, I make firstInt as nil, it will execute else condition. If, instead, I use force-unwrap with firstInt that would lead to crash, something like this:

Accessing valueless implicitly unwrapped optional?

I am curious about the way implicitly unwrapped optionals work, in the Apple reference book - The Swift Programming Language it states:
“If you try to access an implicitly unwrapped optional when it does
not contain a value, you will trigger a runtime error. The result is
exactly the same as if you place an exclamation mark after a normal
optional that does not contain a value.”
If I try and access a valueless optional without an exclamation mark you get an error as stated above.
var optionalVar:String?
println("VAR: \(optionalVar!)")
If however you try an access an implicitly unwrapped optional that does not contain a value the println outputs VAR: nil which is not what is stated above.
var implicitOpt:String!
println("VAR: \(implicitOpt)")
Can anyone clarify this, is it badly worded docs, me miss understanding, a bug?
Thing is that you are not unwrapping the value in this case, but printing unwrapped optional as special type. Weird, I know. Try casting it to normal String and it will crash if nil:
var implicitOpt: String!
println("VAR: \(implicitOpt as String)")
The following lines are equal:
var implicitOpt: ImplicitlyUnwrappedOptional<String>
var implicitOpt: String!
ImplicitlyUnwrappedOptional conforms to Printable protocol. So the string interpolation
"\(implicitOpt)"
will call description on ImplicitlyUnwrappedOptional instance and not String instance. Thats why optional is not unwrapped in this case.
When you define it as a implicitly unwrapped optional ,the compiler expects it to be initialised and already holding a value .
If you try to do any operation on the variable it will throw you a run time error .
You can observe that evaluation doesn't throw any runtime error ,it will give you nil (look at the if loop where it is evaluated)
var implicitOpt:String!
print("VAR: \(implicitOpt)")
var someValue = 10;
if let x = implicitOpt
{
someValue=1;
}
else
{
someValue=2
}
var b = implicitOpt;
b = b + "asdf"
let a = implicitOpt + "asdf"

Resources