49

It starts out as an empty string instead of nil. Even when it is explicitly set to nil it remains an empty string. I don't get it. Perhaps to make it easy to clear by assigning nil? Writing code with it is clunky.

var textField = UITextField()
print(textField.text) // prints "Optional("")"
textField.text = nil
print(textField.text) // prints "Optional("")"
Verticon
  • 2,419
  • 16
  • 34
  • 4
    Related (duplicate?): [Why was UITextField's text property changed to an optional in Swift 2?](http://stackoverflow.com/questions/32621022/why-was-uitextfields-text-property-changed-to-an-optional-in-swift-2) – Martin R Mar 17 '17 at 15:42
  • @MartinR Not a duplicate, I think. The question here is _why_ `text` is an Optional, since it is never `nil`. The question _there_ is how to _treat_ `text` given that it _is_ an Optional. – matt Mar 17 '17 at 15:44
  • @matt: At least closely related. The title there says "*Why ...*" – Martin R Mar 17 '17 at 15:47
  • 1
    @MartinR But none of the answers answer that. They are only about _how_ (to cope). Sulthan's is the first attempt at an answer to this question that I've ever seen. – matt Mar 17 '17 at 15:55
  • @matt: Agreed.. – Martin R Mar 17 '17 at 16:01
  • To me, this question is about a design decision made by Apple, which is off topic for Stack Overflow as a primarily opinion-based question (only the Apple engineers who wrote the code can answer). – JAL Mar 17 '17 at 16:04
  • @JAL I think it's worse than that; I think it's fair to call it a bug, and I've added an answer saying so. – matt Mar 17 '17 at 17:00

2 Answers2

46

This is a historical thing. UITextField does not make any difference between an empty string and a nil string. In Objective-C there was no need to make a difference between them because you can call methods on nil in Objective-C.

Also, there was no way in Objective-C to prevent users from assigning nil to a property. The resulting contract is that text can be optional. In Objective-C that makes no difference.

In Swift there is not much we can do because UITextField.text contract would have to change, possibly breaking lots of already written code. Note that even if nil is never returned from the method, you can still assign nil to reset the value.

You can find hundreds of similar situations in the old APIs.

Sulthan
  • 128,090
  • 22
  • 218
  • 270
  • 2
    So, does that mean that I can always force unwrap it? – Verticon Mar 17 '17 at 15:34
  • 5
    @Verticon No, you can always use `?? ""`. – Sulthan Mar 17 '17 at 15:35
  • Are you sure? Check out my edited question: even after assigning nil it still returns .some("") – Verticon Mar 17 '17 at 15:39
  • Actually you can create an extension to UITextField and add a string property to `return text ?? ""` http://stackoverflow.com/a/35692194/2303865 – Leo Dabus Mar 17 '17 at 15:40
  • @Verticon I don't think you understand my explanation. I am explaining why `text` is an optional. I haven't said you don't have to handle the optional. – Sulthan Mar 17 '17 at 15:40
  • @Sulthan Thank you for your answer and it makes sense. I was just pointing out that it seems to never be nil and that therefore I could always force unwrap it. Perhaps I should treat this as undocumented behavior upon which I should not rely? – Verticon Mar 17 '17 at 15:46
  • 4
    In the current UIKit implementation, `text` will never be nil. However, it's not documented as such, so it's safer to assume it could be nil. – rob mayoff Mar 17 '17 at 15:51
  • 7
    I'm not sure this really answers the question. I _can't_ "find hundreds of similar situations." The whole idea of hand-tweaking the APIs was to remove unnecessary Optionals. Hundreds of values can _theoretically_ be `nil` but in fact never will be, and in Swift they are therefore _not_ Optionals. _This_ value can never be `nil`; even if Objective-C code sets it to `nil`, it doesn't become `nil`. And making it nonOptional in Swift wouldn't "break" anything whatever. So it makes no sense that it's an Optional in Swift. I think the right answer is that it's a bug. – matt Mar 17 '17 at 16:34
  • @matt There is valid objective-c and even Swift code calling `field.text = nil`. Making `text` non optional would make all that code invalid. Therefore making the property non-optional is not that easy. – Sulthan Mar 17 '17 at 16:37
  • 11
    The Swift code calling `field.text = nil` would simply have to be replaced by `field.text = ""`. No worse than the kind of breakage we've been through dozens of times during the Swift version-update process. And the Objective-C code could just go on working. – matt Mar 17 '17 at 16:38
34

I feel strongly enough about this that I'm repeating my comment on Sulthan's answer as an alternative answer.

I'm not sure Sulthan's answer really answers the question.

I can't "find hundreds of similar situations." That's because they are no longer there. They were there in Swift 1, but that was a long time ago. Since then, the APIs have been hand-tweaked to eliminate them. This one wasn't eliminated.

The whole idea of hand-tweaking the APIs was to remove unnecessary Optionals. Hundreds of values can theoretically be nil but in fact never will be, and in Swift they are therefore not Optionals. This value can never be nil; even if Objective-C code sets it to nil, it doesn't become nil. And making it nonOptional in Swift wouldn't "break" anything whatsoever. So it makes no sense that it's an Optional in Swift.

I think the right answer, therefore, is that it's a bug. During IUO removal in the course of hand-tweaking the APIs in the run-up to Swift 2.0, the label and text field text properties should have been characterized as a nonOptional String, but they weren't.

Cloud
  • 938
  • 1
  • 8
  • 24
matt
  • 515,959
  • 87
  • 875
  • 1,141