What is the difference between String? and String! (two ways to create an optional variable)?

In Quick Language (Apple Book). I read that you can create optional variables in two ways: using a question mark (?) Or using an exclamation point (!).

The difference is that when you get the optional value with (?), You have to use an exclamation point every time you want to get the value:

var str: String? = "Question mark?" println(str!) // Exclamation mark needed str = nil 

So far with the help of (!) 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 two ways, if there is no difference at all?

+46
ios swift
Jun 06 '14 at 2:09
source share
6 answers

The real benefits of using implicitly deployed options (declared with!) Are related to class initialization, when two classes point to each other, and you need to avoid a strong reference loop. For example:

Class A ↔ Class B

A procedure of class A init should create (and its own) class B, and B needs a weak appeal 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 requires a reference to class A, which must be initialized.
  • Class A can only pass self to the initializer of class B after full initialization.
  • In order for class A to be considered initialized before class B is created, the instanceOfB property must be optional.

However, once A was created, it would be very annoying to have access to instanceOfB using instanceOfB! since we know what should be B

To avoid this, instanceOfB is declared as an optional (optional) instance (instanceOfB!), And we can access it using only instanceOfB. (In addition, I suspect that the compiler can also optimize access in different ways).

An example of this is shown on pages 464 through 466 of the book.

Summary:

  • Use? if the value can become zero in the future, so you check it out.
  • Use! if it really does not become zero in the future, but first it should be zero.
+54
Jun 06 '14 at
source share

You must go beyond syntactic sugar.

There are two completely different polymorphic types. Syntactic sugar simply uses one or the other of these types.

When do you write Foo? as a type, you really have Optional<Foo> , and when you write Foo! you really have ImplicitlyUnwrappedOptional<Foo> .

These are two different types, and they differ from Foo .

+6
Jun 06 '14 at 2:54
source share

Type String! called implicitly deployed optional:

Sometimes it can be seen from the structure of programs that optional always matters, after which the value is first set. In these cases, it is useful to remove the need to check and expand the value of the options each time it is accessed, since it is safe to assume that the value is all the time.

These types of options are defined as implicitly deployed OPTIONAL. You write an implicitly expanded option by placing an exclamation mark (String!), Rather than a question mark (String?) After the type you want to make optional.

+2
Jun 06 '14 at 14:17
source share

Values ​​created with ? are the usual optional values, as you mentioned, you must access it through an optional binding ( if let unwrappedValue = myOptionalValue ) or using the exclamation point syntax myOptionalValue!.doSomething() .

Values ​​created using ! are called implicitly expanded options. With them, you do not need to manually unpack them before using them. When you execute val myOptionalValue!.doSomething() .

The value will be automatically expanded for you when you use myOptionalValue directly, be careful with this because accessing the implicitly expanded value when it has no value (when it is nil ) will result in a runtime error.

+2
Jun 06 '14 at 14:17
source share

in the optional chain you will find the answer:

class example:

 class Person { var residence: Residence? } class Residence { var numberOfRooms = 1 } 

If you try to access the numberOfRomoms property of this place of residence of people by placing an exclamation mark after the residence to force it to expand, you cause a runtime error because there is no place of residence to turn:

 let roomCount = john.residence!.numberOfRooms // this triggers a runtime error 

The above code succeeds when the john.residence value is non-zero and sets the roomCount value for the Int value containing the corresponding number of rooms. However, this code always causes a runtime error when the residence is zero, as shown above.

An optional chain provides an alternative way to access the value of numberOfRooms. To use an extra string, use a question mark instead of an exclamation mark:

 if let roomCount = john.residence?.numberOfRooms { println("John residence has \(roomCount) room(s).") } else { println("Unable to retrieve the number of rooms.") } // prints "Unable to retrieve the number of rooms." 
+1
Jun 06 '14 at 14:20
source share

Well, the above @tarmes. Noticed another use of implicit optional:

Suppose I have an optional Int :

 let firstInt: Int? = 9 

And I'm trying to use the optional pattern matching and use this optional Int as follows:

 if case let myFirstInt? = firstInt where myFirstInt > 1 { print("Valid") } else { print("Invalid") } 

Note that I am using an implicit optional parameter with the local parameter myFirstInt , which makes it safe for the nil condition associated with the optional firstInt . If now, I do firstInt as nil , it will fulfill the else condition. If instead I use force-unwrap with firstInt , which will crash, something like this:

enter image description here

+1
May 17 '16 at 10:07
source share



All Articles