Подтвердить что ты не робот

Как получить значение, связанное с быстрым перечислением, независимо от случая перечисления

У меня есть объект FormField, который имеет два свойства: String name и a value, которые могут принимать любой тип - поэтому я сделал его Any!. Тем не менее, мне сказали в отдельный вопрос использовать перечисление со связанными значениями вместо Any!.

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

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

Этот подход делает ужасно подробным для проверки недействительности. Если бы я хотел отобразить представление предупреждения для всех недостающих полей в форме, мне придется повторить проверку nil для каждого случая в инструкции switch:

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)
            }
        }
    }
}

Существует ли более короткий способ доступа к связанному с перечислением значению независимо от типа? Если я сделаю FormField.value a Any!, приведенный выше код будет таким же простым, как:

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

Ответ 1

Определите метод isMissing() внутри enum - напишите его один раз и только один раз. Тогда вы получите почти то, что вы предпочитаете:

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

Это будет выглядеть примерно так (от 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

Ответ 2

С Swift 2 можно получить связанное значение с помощью отражения.

Чтобы упростить просто добавление кода в проект и расширение вашего перечисления с помощью протокола EVAssociated.

    public protocol EVAssociated {
    }

    public extension EVAssociated {
        public var associated: (label:String, value: Any?) {
            get {
                let mirror = Mirror(reflecting: self)
                if let associated = mirror.children.first {
                    return (associated.label!, associated.value)
                }
                print("WARNING: Enum option of \(self) does not have an associated value")
                return ("\(self)", nil)
            }
        }
    }

Затем вы можете получить доступ к указанному значению с помощью кода следующим образом:

    class EVReflectionTests: XCTestCase {
            func testEnumAssociatedValues() {
                let parameters:[EVAssociated] = [usersParameters.number(19),
usersParameters.authors_only(false)]
            let y = WordPressRequestConvertible.MeLikes("XX", Dictionary(associated: parameters))
            // Now just extract the label and associated values from this enum
            let label = y.associated.label
            let (token, param) = y.associated.value as! (String, [String:Any]?)

            XCTAssertEqual("MeLikes", label, "The label of the enum should be MeLikes")
            XCTAssertEqual("XX", token, "The token associated value of the enum should be XX")
            XCTAssertEqual(19, param?["number"] as? Int, "The number param associated value of the enum should be 19")
            XCTAssertEqual(false, param?["authors_only"] as? Bool, "The authors_only param associated value of the enum should be false")

            print("\(label) = {token = \(token), params = \(param)")
        }
    }

    // See http://github.com/evermeer/EVWordPressAPI for a full functional usage of associated values
    enum WordPressRequestConvertible: EVAssociated {
        case Users(String, Dictionary<String, Any>?)
        case Suggest(String, Dictionary<String, Any>?)
        case Me(String, Dictionary<String, Any>?)
        case MeLikes(String, Dictionary<String, Any>?)
        case Shortcodes(String, Dictionary<String, Any>?)
    }

    public enum usersParameters: EVAssociated {
        case context(String)
        case http_envelope(Bool)
        case pretty(Bool)
        case meta(String)
        case fields(String)
        case callback(String)
        case number(Int)
        case offset(Int)
        case order(String)
        case order_by(String)
        case authors_only(Bool)
        case type(String)
    }

Вышеприведенный код теперь доступен как кокоапод susbspec в https://github.com/evermeer/Stuff#enum Он также имеет другое красивое расширение enum для перечисления всех значений перечисления.