I have a custom object called Field. I basically use it to define a single field in a form.
class Field {
var name: String
var value: Any?
// initializers here...
}
When the user submits the form, I validate each of the Field
objects to make sure they contain valid values. Some fields aren't required so I sometimes deliberately set nil
to the value
property like this:
field.value = nil
This seems to pose a problem when I use an if-let to determine whether a field is nil or not.
if let value = field.value {
// The field has a value, ignore it...
} else {
// Add field.name to the missing fields array. Later, show the
// missing fields in a dialog.
}
I set breakpoints in the above if-else and when field.value
has been deliberately set to nil, it goes through the if-let block, not the else. However, for the fields whose field.value
I left uninitialized and unassigned, the program goes to the else block.
I tried printing out field.value
and value
inside the if-let block:
if let value = field.value {
NSLog("field.value: \(field.value), value: \(value)")
}
And this is what I get:
field.value: Optional(nil), value: nil
So I thought that maybe with optionals, it's one thing to be uninitialized and another to have the value of nil. But even adding another if inside the if-let won't make the compiler happy:
if let value = field.value {
if value == nil { // Cannot invoke '==' with an argument list of type '(Any, NilLiteralConvertible)'
}
}
How do I get around this? I just want to check if the field.value
is nil
.
I believe this is because Any?
allows any value and Optional.None
is being interpreted as just another value, since Optional
is an enum!
AnyObject?
should be unable to do this since it only can contain Optional.Some([any class object])
, which does not allow for the case Optional.Some(Optional)
with the value Optional.None
.
This is deeply confusing to even talk about. The point is: try AnyObject?
instead of Any?
and see if that works.
More to the point, one of Matt's comment mentions that the reason he wants to use Any
is for a selection that could be either a field for text input or a field intended to select a Core Data object.
The Swifty thing to do in this case is to use an enum with associated values, basically the same thing as a tagged/discriminated union. Here's how to declare, assign and use such an enum:
enum DataSelection {
case CoreDataObject(NSManagedObject)
case StringField(String)
}
var selection : DataSelection?
selection = .CoreDataObject(someManagedObject)
if let sel = selection { // if there's a selection at all
switch sel {
case .CoreDataObject(let coreDataObj):
// do what you will with coreDataObj
case .StringField(let string):
// do what you will with string
}
}
Using an enum like this, there's no need to worry about which things could be hiding inside that Any?
. There are two cases and they are documented. And of course, the selection variable can be an optional without any worries.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With