无论枚举情况如何,如何获得快速枚举的相关值

时间:2023-01-26 14:33:37

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!.

我有一个对象FormField,它有两个属性:一个字符串名称和一个可以接受任何类型的值 - 因此我已经使它成为任何!但是,我在一个单独的问题中被告知要使用带有相关值的枚举而不是任何!

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:

然而,这种方法使得检查无效非常冗长。如果我想显示表单中所有缺少字段的警报视图,我将不得不对switch语句中的每个案例重复nil检查:

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:

无论类型如何,是否有更短的方式来访问枚举的相关值?如果我使FormField.value成为Any!上面的代码就像这样简单:

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

2 个解决方案

#1


9  

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

在枚举中定义一个方法isMissing() - 只写一次。然后你几乎完全得到你喜欢的东西:

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

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

它看起来像这样(来自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


6  

With Swift 2 it's possible to get the associated value using reflection.

使用Swift 2,可以使用反射获得相关值。

To make that easier just add the code below to your project and extend your enum with the EVAssociated protocol.

为了更容易,只需将下面的代码添加到您的项目中,并使用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)
            }
        }
    }

Then you can access the .asociated value with code like this:

然后,您可以使用以下代码访问.asociated值:

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

The code above is now available as a cocoapod susbspec at https://github.com/evermeer/Stuff#enum It also has an other nice enum extension for enumerating all enum values.

上面的代码现在可以作为cocoapod susbspec在https://github.com/evermeer/Stuff#enum上获得。它还有一个其他很好的枚举扩展,用于枚举所有枚举值。

#1


9  

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

在枚举中定义一个方法isMissing() - 只写一次。然后你几乎完全得到你喜欢的东西:

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

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

它看起来像这样(来自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


6  

With Swift 2 it's possible to get the associated value using reflection.

使用Swift 2,可以使用反射获得相关值。

To make that easier just add the code below to your project and extend your enum with the EVAssociated protocol.

为了更容易,只需将下面的代码添加到您的项目中,并使用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)
            }
        }
    }

Then you can access the .asociated value with code like this:

然后,您可以使用以下代码访问.asociated值:

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

The code above is now available as a cocoapod susbspec at https://github.com/evermeer/Stuff#enum It also has an other nice enum extension for enumerating all enum values.

上面的代码现在可以作为cocoapod susbspec在https://github.com/evermeer/Stuff#enum上获得。它还有一个其他很好的枚举扩展,用于枚举所有枚举值。