6

I have read this question and some other questions. But they are somewhat unrelated to my question

For UILabel if you don't specify ? or ! you will get such an error:

@IBOutlet property has non-optional type 'UILabel'

Which then Xcode gives you 2 choices to have it fixed, you can do:

fix-it Add ? to form the optional type UIlabel?
fix-it Add ! to form the implicitly unwrapped optional type UIlabel?

However for string you can just type string without ? or ! and you won't get an error why is that?

What happens if the name isn't set? Then we would have a nil isn't using ?, ! and Swift all about satisfying 'type-safety'?

Example:

struct PancakeHouse {
  let name: String // this doesn't have '?' nor '!'
  let photo: UIImage?
  let location: CLLocationCoordinate2D?
  let details: String
}

My major confussion is when would we want to not use Optional?

4 Answers 4

9

All this is covered in the documentation: The Swift Programming Language - The Basics.

In short:

String represents a String that's guaranteed to be present. There is no way this value can be nil, thus it's safe to use directly.

String? represents a Optional<String>, which can be nil. You can't use it directly, you must first unwrap it (using a guard, if let, or the force unwrap operator !) to produce a String. As long as you don't force unwrap it with !, this too is safe.

String! also represents an Optional<String>, which can be nil. However, this optional can be used where non-optionals are expected, which causes implicit forced unwrapping. It's like having a String? and having it always be implicitly force unwrapped with !. These are dangerous, as an occurrence of nil will crash your program (unless you check for nil manually).

Sign up to request clarification or add additional context in comments.

11 Comments

Can you elaborate your last paragraph? My major confusion was actually string vs string!, and I thought ALL objects are optionals...I mean there is not such thing as 'string type', there is only 'optional string' as a type
I strongly suggest you give a good read through the link I posted. It explains all this quite well. Optional is just an enumeration. It either has a value of None or Some. In the latter case, it has an underlying value associated with it. When you say something like let s : String! = "a string", you're just using short form for let s : Optional<String> = Optional("a string"), with the added consequence that all accesses of the var try to force unwrap the value within.
I have read those paragraphs and your post numerous times, still I am a bit confused about the difference between String and String!, they would both crash during runtime—if the value is nil. right? Is that what that makes them different? Would it made any sense if we used String! for name or details?
@Honey they would both crash during runtime—if the value is nil. right? From my answer: String represents a String that's guaranteed to be present. There is no way this value can be nil, thus it's safe to use directly.
@Honey Yes, that's the whole point of Optionals: to eliminate/reduce the run time uncertainty of nil values, and move the error handling as much as possible into compile time checks. That's why implicitly unwrapping (String!) is so discouraged, because it essentially waives these features entirely.
|
7

For your PancakeHouse struct, name is non-optional. That means that its name property cannot be nil. The compiler will enforce a requirement that name be initialized to a non-nil value anytime an instance of PancakeHouse is initialized. It does this by requiring name to be set in any and all initializers defined for PancakeHouse.

For @IBOutlet properties, this is not possible. When an Interface Builder file (XIB or Storyboard) is unarchived/loaded, the outlets defined in the IB file are set, but this always occurs after the objects therein have been initialized (e.g. during view loading). So there is necessarily a time after initialization but before the outlets have been set, and during this time, the outlets will be nil. (There's also the issue that the outlets may not be set in the IB file, and the compiler doesn't/can't check that.) This explains why @IBOutlet properties must be optional.

The choice between an implicitly unwrapped optional (!) and a regular optional (?) for @IBOutlets is up to you. The arguments are essentially that using ! lets you treat the property as if it were non-optional and therefore never nil. If they are nil for some reason, that would generally be considered a programmer error (e.g. outlet is not connected, or you accessed it before view loading finished, etc.), and in those cases, failing by crashing during development will help you catch the bug faster. On the other hand, declaring them as regular optionals, requires any code that uses them to explicitly handle the case where they may not be set for some reason. Apple chose implicitly unwrapped as the default, but there are Swift programmers who for their own reasons, use regular optionals for @IBOutlet properties.

6 Comments

Hmm... So it's the 'enforced initializer' that is making the difference! Thanks!
Does this mean implicit unwrapping is only used for IBOutlets? And about the difference of 'string' and 'string!' 'string' will never crash ur app because of an initializer...however 'string!' may crash the app if not set? Right?
No, implicit unwrapping can be used for any optional. Implicitly unwrapped optionals (like string!) will crash if the value is in fact nil. You're generally meant to use ! only in case where you know for sure that a value will not be nil, and such cases are rare. There are some who would argue that good Swift code never uses !. This is all covered in the Swift book (see the section "Implicitly Unwrapped Optionals).
I have been reading the book for quite some time now. I believe I have a tiny bit of better understanding now and I guess the root of my question is: when should we use an optional and when we shouldn't or basically when should we want our program to crash by not setting an implicit unwrapped property? When should we want our program to give error for not setting a stored property?
After learning from all answers, I got to write an answer. Can you please comment/correct my own answer and see if it addresses the question better than yours (No offense), as my major point of confusion was String vs String!
|
1

The whole "optional" thing messed with me bad at first. What made it "click" for me, was when I stopped thinking of those as "String" objects and started thinking of them as generics. Just like "Array" with generic identifier for "String" is an array that, if it has values, contains strings... "String?" is an Optional that, if it has a value, is a string.

String - This is always guaranteed to be some kind of string, and NEVER nil. When you declare a variable, it must be given a value.

String? - This is an optional. It can be nil, and IF it has a value, it will be a string. In order to access the optional's value, you must unwrap it.

String! - This is an optional, with syntax sugar that lets you access its value directly as if it where just a String. It COULD be nil, but for whatever reason, the context around the variable has winked at you and said "don't worry, it will have a value."

Comments

0

Thanks to Andrew Madsen's answer and all other answers, I learnt a bit myself:

struct pairOfOptionalAndNonOptionalAndImplicitUnwrapped{
    var word1 :String?
    var word2 :String
    var word3: String!

    init (a:String, b: String, c: String){
        self.word1 = a // Line A
        self.word2 = b // Line B
        self.word3 = c // Line C
    } //Line BBBB


    func equal() ->Bool{
        return word1 == word2 + word3
    }
}

let wordParts = pairOfOptionalAndNonOptionalAndImplicitUnwrapped (a:"partTwo", b: "part", c:"Two")
wordParts.equal() // Line CCCC

  • If I comment out Line A only, I will get no errors, because it is optional, and optionals can be set to nil.
  • If I comment out Line B only, I will get a compilation error on Line BBBB, saying: Return from initializer without initializing all stored properties, I get this because I have declared property word2 as non-optional. I have told the compiler I have guaranteed to have you set...
  • If I comment out Line C only, I will not get an error, unless I actually run a method on my object. The error you could get is: Execution was interrupted, reason: EXC_BAD_INSTRUCTION (code=EXC_1386_INVOP, subcode=0x0) if and only if I run wordParts.equal(), because I told my code that it's an optional meaning that it will be set from elsewhere after instantiation/compilation. Meaning that lldb can through me a runtime error if you it didn't get set. ( the error would happen on line CCCC)

6 Comments

Not exactly cool to do this. It would be better to have made these comment replies to others answers, to properly attribute their work
@AMomchilov I don't have a habit of doing this. It was just that 'to the best of my understanding' the combination of all answers didn't explain the String vs String!. Also I did ask him to look into my answer before accepting my own. It's not like I gained points as a matter of fact I lost 2 points. And I attributed their work in the first line. Do you see any technical issue with my answer?
It's just a matter of convention on SO. It's generally not well received to post an answer as a "guess" and then to ask for confirmation from others, whether it be to your own question, or otherwise. This sort of thing is what comments are for. You can ask other OPs to clarify their answers, or even suggest edits yourself.
@AMomchilov Thanks for the extra explanation. I see what you are saying. But I couldn't fit all that into a comment. :)
Furthermore, my answer distinguished String and String! quite clearly in my opinion. If you found it unclear, you could always ask for clarification and I'd be more than happy to help you out.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.