0
protocol textingprotocol : class {
    func didEnterText (text:String)
}

class secondViewController: UIViewController {    
weak var delegate:textingprotocol?

@IBOutlet weak var txtField: UITextField?

@IBAction func dismissButton(sender: UIButton) {

    delegate!.didEnterText(txtField?.text) // A: doesn't work
    delegate!.didEnterText(txtField?.text!) // B: doesn't work
    delegate!.didEnterText((txtField?.text)!) // C: works

}

A: Am I not already doing optional chaining and the line would only work if text has a value if not then it would gracefully fail? Yet it gives:

Value of optional type 'String?' not unwrapped; did you mean to use '!' or '?'?

B: Even when I am given compiler error of above, well I do unwrap it, still it's not satisfied it wants it to be like C. To my understanding with the ? I have unwrapped txtField and with the ! I have unwrapped text, still confused why it doesn't work

Why does C work but not B? Isn't there a more cleaner way than line C? Line C looks very unappealing.

mfaani
  • 33,269
  • 19
  • 164
  • 293
  • 1
    should be `@IBOutlet weak var txtField: UITextField!` – Leo Dabus Sep 28 '16 at 20:23
  • @LeoDabus Hah. thanks. but looking into the `text` property. Why is that an optional? I mean why I Cmmd+click it it shows `@property (nonatomic, readonly) NSString *text;` it doesn't show anything of like `text:String?` how is it underneath from Objective-c translated to an optional? – mfaani Sep 28 '16 at 20:26
  • I'm no swift expert, so I'll leave a comment rather than an answer... `didEnterText` requires a non-nil value, so my understanding is that with option B if `txtField` is nil the `.text` part of that statement wouldn't even be evaluated, and as such adding the `.text!` doesn't fix the issue of a nil text field. In option C all the compiler sees is a value that is "guaranteed" to be non-nil because the whole thing is wrapped in parens... – Mike Sep 28 '16 at 20:36
  • 1
    How is `textingprotocol` defined, please? – matt Sep 28 '16 at 20:41
  • @matt see the update – mfaani Sep 28 '16 at 20:43
  • So this is some form of Swift 2? – matt Sep 28 '16 at 20:45
  • @matt not sure :| , but on my Xcode 8, I have enabled `Use Legacy Swift Language Version` to be able to use 2.x, though when I do `xcrun swift -version` I get `Apple Swift version 3.0 ` – mfaani Sep 28 '16 at 20:47
  • Right, I understand. :) Okay, I'm ready to answer, hang on a sec. – matt Sep 28 '16 at 20:49
  • @matt Thanks boss. Experts like you help newbies like me make our livings. Super thanks. – mfaani Sep 28 '16 at 21:01

1 Answers1

2

didEnterText does not take a String?. It takes a String. Thus, you cannot use simple optional chaining with question marks to get its argument. You must actually unwrap to a String, not tentatively unwrap to a String?-or-nil.

Now, txtField is an Optional, so you need to unwrap it.

And a UITextField's text property is an Optional, so you need to unwrap it too.

So the simplest approach is to unwrap them both, absolutely:

    delegate!.didEnterText(txtField!.text!)

If you don't want to do that (because you fear that one of them will be nil and crash your app), you will have to protect the whole thing with if let:

    if let s = txtField?.text {
        delegate!.didEnterText(s)
    }
matt
  • 515,959
  • 87
  • 875
  • 1,141
  • so basically you are saying an non-optional will NEVER work with optionals unless it's guaranteed by using `!` ie not `?` right? – mfaani Sep 28 '16 at 20:54
  • I don't quite know what you mean. The simple fact is that you cannot supply a `String?` where a `String` is expected. The `String` is hidden inside the `String?`. You must unwrap it! You can unwrap it unsafely with `!` or safely and conditionally with `if let`, but you must unwrap it before you can use it. – matt Sep 28 '16 at 20:57
  • 1
    It almost seems as if you are not entirely clear on what an Optional _is_. If that's the case, my book will help you: http://www.apeth.com/swiftBook/ch03.html#_optional – matt Sep 28 '16 at 20:58
  • :) perhaps. I thought I knew, but it's the optional chaining part that is confusing, but now it seems that if you try to unwrap a value through `?` you can't assign that value to something that is non-optional. Since it's not guaranteeing a value—it could *still* be nil. – mfaani Sep 28 '16 at 20:59
  • 1
    Optional chaining with `?` has the advantage that you won't crash, but it can only end up with an Optional. You still need to unwrap it! It think that might be the fact that you are missing. – matt Sep 28 '16 at 21:08