Search code examples
ioscocoacocoa-touchswift

How to get a swift enum's associated value regardless of the enum case


I have an object FormField which has two properties: a String name, and a value which can accept any type--hence I've made it Any!. However, I've been told in a separate question to use an enum with associated values instead of Any!.

enum Value {
    case Text(String!)
    case CoreDataObject(NSManagedObject!)
}

class FormField {
    var name: String
    var value: Value?
    // initializers...
}

This approach makes it awfully verbose to check for nullity however. If I wanted to display an alert view for all the missing fields in the form, I'll have to repeat a nil check for every case in a switch statement:

for field in self.fields {
    if let value = field.value {
        switch value {
        case .Text(let text):
            if text == nil {
                missingFields.append(field.name)
            }
        case .CoreDataObject(let object):
            if object == nil {
                missingFields.append(field.name)
            }
        }
    }
}

Is there a shorter way of accessing the enum's associated value, regardless of the type? If I make FormField.value an Any! the above code would be as easy as:

for field in self.fields {
    if field.value == nil {
        missingFields.append(field.name)
    }
}

Solution

  • Define a method isMissing() inside the enum - write it once and only once. Then you get nearly exactly what you prefer:

    for field in self.fields {
        if field.value.isMissing() {
            missingFields.append(field.name)
        }
    }
    

    It would look something like this (from the Swift Interpreter):

      1> class Foo {}
       >
      2> enum Value { 
      3.     case One(Foo!) 
      4.     case Two(Foo!) 
      5.      
      6.     func isMissing () -> Bool { 
      7.         switch self { 
      8.         case let .One(foo): return foo == nil 
      9.         case let .Two(foo): return foo == nil 
     10.         } 
     11.     } 
     12. }    
     13> let aVal = Value.One(nil)
    aVal: Value = One {
      One = nil
    }
     14> aVal.isMissing()
    $R0: Bool = true