我有一个对象FormField,它有两个属性:一个是字符串name
,另一个是可以接受任何类型的value
--因此我将其设为Any!
。但是,我在a separate question中被告知要使用带有关联值的枚举,而不是Any!
。
enum Value {
case Text(String!)
case CoreDataObject(NSManagedObject!)
}
class FormField {
var name: String
var value: Value?
// initializers...
}
然而,这种方法使得检查空性变得非常冗长。如果我想要显示表单中所有缺少的字段的警报视图,我将不得不对switch语句中的每个case重复执行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)
}
}
}
}
有没有一种更短的方法来访问枚举的关联值,而不管类型是什么?如果我让FormField.value成为一个Any!
,上面的代码将非常简单:
for field in self.fields {
if field.value == nil {
missingFields.append(field.name)
}
}
发布于 2014-09-17 09:55:42
在enum
中定义一个方法isMissing()
--只写一次。然后你就会得到你想要的东西:
for field in self.fields {
if field.value.isMissing() {
missingFields.append(field.name)
}
}
它看起来像这样(来自Swift解释器):
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
发布于 2015-09-15 19:31:33
在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)
}
}
}
然后,您可以使用如下代码访问.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)
}
上面的代码现在可以在https://github.com/evermeer/Stuff#enum上作为cocoapod susbspec使用,它还有另一个很好的枚举扩展,可以枚举所有枚举值。
发布于 2019-02-14 23:47:52
如果所有枚举用例的关联值都属于同一类型,则以下方法可能会有所帮助。
enum Value {
case text(NSString!), two(NSString!), three(NSString!) // This could be any other type including AnyClass
}
// Emulating "fields" datastruct for demo purposes (as if we had struct with properties).
typealias Field = (en: Value, fieldName: String)
let fields: [Field] = [(.text(nil),"f1"), (.two(nil), "f2"), (.three("Hey"), "f3")] // this is analog of "fields"
let arrayOfFieldNamesWithEmptyEnums: [String] = fields.compactMap({
switch $0.en {
case let .text(foo), let .two(foo), let .three(foo): if foo == nil { return $0.fieldName } else { return nil }}
})
print("arrayOfFieldNamesWithEmptyEnums \(arrayOfFieldNamesWithEmptyEnums)")
许多其他的东西也可以得到类似的结果。
let arrayOfEnumsWithoutValues: [Value] = fields.compactMap({
switch $0.en {
case let .text(foo), let .two(foo), let .three(foo): if foo == nil { return $0.en } else { return nil }}
})
print("arrayOfEnumsWithoutValues \(arrayOfEnumsWithoutValues)")
// just to check ourselves
if let index = arrayOfEnumsWithoutValues.index(where: { if case .two = $0 { return true }; return false }) {
print(".two found at index \(index)")
}
https://stackoverflow.com/questions/25880789
复制相似问题