Как получить связанное значение SWIFT enum независимо от случая перечисления
у меня есть объект FormField, который имеет два свойства: строка name
и value
который может принимать любой тип-следовательно, я сделал это Any!
. Однако мне сказали в отдельный вопрос использовать перечисление со связанными значениями вместо Any!
.
enum Value {
case Text(String!)
case CoreDataObject(NSManagedObject!)
}
class FormField {
var name: String
var value: Value?
// initializers...
}
этот подход делает его ужасно многословным, чтобы проверить на ничтожность, однако. Если я хочу отобразить вид предупреждения для всех отсутствующих полей в форме, мне придется повторить нулевую проверку для каждого случая в операторе 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.значение Any!
приведенный выше код будет таким же простым, как:
for field in self.fields {
if field.value == nil {
missingFields.append(field.name)
}
}
2 ответов
определить способ isMissing()
внутри enum
- написать его один раз и только один раз. Тогда вы получите почти точно то, что вы предпочитаете:
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
С 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)
}
код выше теперь доступен как cocoapod susbspec на https://github.com/evermeer/Stuff#enum Он также имеет другое хорошее расширение enum для перечисление всех значений enum.