1

I have this test class:

class OrderParserTests: XCTestCase {

    var previewJson : String!

    override func setUp(){
        let path = Bundle(for: type(of: self)).path(forResource: "orderDocumentPreviewResponse", ofType: "json") ?? ""
        self.previewJson = try! String(contentsOfFile: path)
    }

    func testStandardOrder(){
        ...
    }
}

previewJson is of type String, but I don't need an initializer to set it and it starts with a default value of nil even though it's a non optional field (I think).

Am I misunderstanding what ! does to fields?

What is the difference between

var previewJson: String?

and

var previewJson: String!
bio595
  • 446
  • 2
  • 4
  • 11
  • First see [here](https://stackoverflow.com/questions/37400196/why-optional-constant-does-not-automatically-have-a-default-value-of-nil) then [here](http://stackoverflow.com/questions/27797351/class-has-no-initializers-swift/40769917#40769917). They *indirectly* help you get a better picture of optionals – mfaani Feb 16 '17 at 23:00
  • Also see [here](https://stackoverflow.com/questions/37493241/swift-string-vs-string-vs-string) – mfaani Feb 16 '17 at 23:08

2 Answers2

3

String! is an implicitly unwrapped optional. It will still crash your app if you attempt to access its value when it is nil and you do not expect it. Implicitly unwrapped optionals are useful for variables which you cannot set the value for at initialization but know you will certainly set before use. Relevant:

An implicitly unwrapped optional is a normal optional behind the scenes, but can also be used like a nonoptional value, without the need to unwrap the optional value each time it is accessed.

Neither var previewJson: String? nor var previewJson: String! will require a custom init because they're both setting default values of nil.

garrettmurray
  • 3,338
  • 1
  • 25
  • 23
2

What is the difference between

var previewJson: String?

and

var previewJson: String!

Not much. They are both Optionals, ostensibly wrapping a String. They are both auto-initialized to nil. They are both governed by the same rules. Almost.

The main difference is that with String! you can say things like previewJson.lowercased() without explicitly unwrapping the Optional.

Do you see why that is special? With String? you would have to say previewJson?.lowercased() or previewJson!.lowercased(). You can do the same with String!, but you don't have to, because String! follows a special rule that if you use it where a nonOptional String is expected, it will unwrap the Optional for you.

So a String! is an Optional just like a String? except that, under certain conditions of stress, it will unwrap itself for you. And that's all it is.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • 1
    I should add, however, that `String!` is also dangerous. That's because if it _is_ `nil` and you _do_ say something like `previewJson.lowercased()`, you will crash. A normal Optional makes you think about what you're doing before you crash, but a self-unwrapping Optional will just crash without batting an eyelash. – matt Feb 16 '17 at 23:29