3

I have a string var oneString: String! and later on in a method, when I want to concatenate a string to oneString I have to do this:

oneString! += anyString

If I don't add ! I get an error 'String!' is not identical to 'CGFloat'

If I initialize my string with var oneString = "" I don't have this problem. Why? Why do I need to unwrap oneString while I explicitly said it would not be nil when I declared it?

Nico
  • 6,269
  • 9
  • 45
  • 85
  • 1
    I thought this question with the answer of Anton it can help you to understand what its happens behind the scenes http://stackoverflow.com/questions/24018327/what-does-an-exclamation-mark-mean-in-the-swift-language?rq=1 – Victor Sigler Mar 14 '15 at 23:05

2 Answers2

6

Why do I need to unwrap oneString while I explicitly said it would not be nil when I declared it?

You’ve misunderstood what var oneString: String! means. It does not mean oneString will not be nil. If you declare a type as var oneString: String, then you are declaring a type that cannot be nil.

The type String! is an “implicitly-unwrapped optional”. That is, it’s an optional, much like String?, but one that pretends to be a non-optional sometimes. Mostly for the purposes of reading it – you don’t have to explicitly unwrap it to get the value out. The downside being, if it is ever nil (and it totally can be), your code will trap and abort.

But this pretending-to-not-be-optional only goes so far. You cannot pass a String! to a function as inout when that argument is not an optional. Hence your problem.

Anton’s answer is completely correct in why it won’t work, and his suggested operator overload will make your code compile. But it isn’t the right solution – you should instead avoid using implicitly-unwrapped optionals as they are spring-loaded deathtraps and only to be used in specific circumstances (the most common being with Cocoa UI controls). 999 times out of 1,000 you would be better off with a regular optional or non-optional

Airspeed Velocity
  • 40,491
  • 8
  • 113
  • 118
3

Reason is that Foo, Foo? and Foo! are different types in Swift.

There are certain operators pre-defined for you "out-of-the-box" which allow great deal of transparency between Foo and Foo!, but still these types are not the same.

When it comes to strings, operator

func += (inout left: String!, right: String)

... is simply not defined.

If you declare it like:

func += (inout left: String!, right: String) {
    left = left + right
}

... then your code should compile the way you like it, that is:

oneString! += anyString
0x416e746f6e
  • 9,872
  • 5
  • 40
  • 68