I'm new to swift and I'm having some difficulties understanding on how to use (!) and (?)
As far as I know, we can use (?) when there are instances that a variable can be nil. And use (!) when you are 100% sure that item is not nil.
1. Working Fine - Optionals
var john:String?
john = "Is my name"
println(john!)
2. Crashes on Runtime - ! must not be nil - means this is correct
var john:String?
println(john!)
3. Works Fine
var dict: [String:AnyObject] = Dictionary()
dict["name"] = "John"
var str: String = dict["name"]! as String <--- Taking away the (!) says it's not convertible to String
4. Cannot Run/Build - for me it's similar to 1.
var dict: [String:AnyObject]? = Dictionary() ---error says does not have a member named 'subscript'
dict["name"] = "John"
var str: String = dict["name"]! as String
5. Unexpectedly found nil while unwrapping an optional value
var dict: [String:AnyObject] = Dictionary()
dict["name"]? = "John"
var str: String = dict["name"]! as String
Would be great if someone can help me understand these things. Thanks!
it is a bit misleading interpretation believing when an !
'marks' an ivar then that 100% cannot be nil
. it can be. you can say only, you got the value as already unwrapped, so you don't need to force unwrapping it again – but it can be nil
.
try this example for instance:
var text: String! = "hello"
text = nil;
println(text)
it prints a nil
for you.
the reason why your app can crash is you force unwrapping an optional which is nil
, that is invalid operand.
line-by-line:
var dict: [String:AnyObject]? = Dictionary() // from OP
your dict
is an optional, let us see what you are doing here:
dict["name"] = "John" // from OP
var str: String = dict["name"]! as String // from OP
you have an optional dict
and you'd like to use it somehow, you have two possible ways to do it:
dict?["name"] = "John" // optional chaining
it is quite straightforward, it assigns the new value for the key name
if the dictionary is not nil
, otherwise the chain generously falls and nothing happens in runtime.
in perspective of this line:
var str: String = dict!["name"]! as String // forcibly unwrapped
it crashes in runtime if either the dictionary or the value for the key was nil
(as per the first paragraph says: invalid operand to force unwrapping a nil
), but the str
would be John
if the dictionary and the key both do valid objects.
dict!["name"] = "John" // forcibly unwrapped
it works like a charm and assigns the new value for the key name
if the dict
exists; but if the dict
was nil
, that is a termination point in runtime (aka crash), because nil
cannot be unwrapped forcibly (see above).
line-by-line:
var dict: [String:AnyObject] = Dictionary() // from OP
your dict
is not optional and not even nil
, but the dictionary is literally empty, so no key does exist in it, including the name
.
dict["name"]? = "John" // from OP
var str: String = dict["name"]! as String // from OP
the optional chaining always falls when any of the element of the chain falls – therefore no new value will be assigned in your code, but the falling happens gracefully, so you bypass the first line about assigning the new value, but the app crashes in the second line because the value does not exists and you try to force unwrapping it (see above about invalid operand).
so, you need to drop the optional chaining from the first line, if you want to assign a new value for a non-existing key:
dict["name"] = "John"
the optional chaining is useful if you would not like to change the original dictionary with adding a new key/value, but you would like to override an existing one only:
dict["name"] = "John"
dict["name"]? = "Jack"
in that case the new value will be Jack
, because the optional chaining won't fall as the key name
is already existing with a different value, so it can be and will be overridden; but:
dict["name"] = nil
dict["name"]? = "Jack"
the optional chaining will falls and no new value is assigned here for the key.
NOTE: there would be many other things and ideas which can be told about the concept. the original documentation is available on Apple site under section Swift Resources.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With