【问题标题】:Default value for Enum in SwiftSwift 中枚举的默认值
【发布时间】:2016-10-10 11:03:34
【问题描述】:

我有一个enum

public enum PersonType:String {

 case Cool                       = "cool"
 case Nice                       = "rude"
 case SoLazy                     = "so-lazy"

 public var description: String {
    switch self {
    case .Cool:
        return "Cool person"
    case .Nice:
        return "Nice person"
    case .SoLazy:
        return "its so lazy person"
    }
}


 public var typeImage: String {
    switch self {
    case .Cool:
        return "cool.png"
    case .Nice:
        return "img_nice.png"
    case .Solazy:
        return "lazy.png"
    }
   }  

}

问题我不知道所有的 person 类型键,所以我需要处理 person 类型的默认情况并给它描述将是它的键,如“so-lazy”和默认图像。

假设我从网络服务中得到这个结果:

[
    {
        name: "john",
        key: "cool"
    },
    {
        name: "paul",
        key: "funny"
    }
]

我需要一个默认案例来处理关键“有趣”

这是我在解析和创建人员对象时初始化枚举的方式:

if let personType = PersonType(rawValue:personTypeKey ?? "") {
   self.personType = personType
}

我想要一个else 或更好的方法来处理我的枚举中未知键的情况,并将键作为描述和默认图像提供给它们。

【问题讨论】:

    标签: ios swift data-structures enums swift2


    【解决方案1】:

    另一种适用于 Swift 3 的方法(可能是 2,不知道):

    enum PersonType: String {
        case cool = "cool"
        case nice = "nice"
        case soLazy = "so-lazy"
        case other
    }
    
    let person = PersonType(rawValue: "funny") ?? .other
    

    在这种情况下,person 变量的类型是 PersonType.other。

    这样做的缺点是您不知道 .other 情况的原始字符串值。

    【讨论】:

      【解决方案2】:

      删除原始类型,并使用带有关联值的enum

      public enum PersonType {
          case Cool
          case Nice
          case SoLazy
          case Unknown(String)
          static func parse(s:String) -> PersonType {
              switch s {
                  case "Cool" : return .Cool
                  case "Nice" : return .Nice
                  case "SoLazy" : return .SoLazy
                  default: return Unknown(s)
              }
          }
      }
      

      删除原始类型的缺点是您必须提供一些逻辑来解析已知的enum 值。然而,好处是您可以将任何其他内容放入单个 Unknown 案例中,同时保留实际的“未知”值以供以后使用。

      【讨论】:

      • 这似乎是一个好方法,但是如何在解析和拥有不同的已知和未知键的同时创建新枚举
      • @iOSGeek 调用PersonType.parse(key),它将产生正确的enum 值。注意最后一次编辑。
      • 我会给所有的枚举实例一个关联值(String, UIImage) 有没有办法在全局范围内声明它并给它们标签,例如(typeName:String, imageType:UIImage),让代码更漂亮?
      • 以及如何在没有开关的情况下在解析后访问关联的值。假设我让myPersonType = PersonType.parse(key) 如何从myPersonType 变量中获取关联值?
      • @iOSGeek 您可以在没有switch 的情况下使用case。参见this answer 示例:if case let .Unknown(key) = parsedValue {...}
      【解决方案3】:

      这非常接近,但我希望能够存储可以与之关联的值,就像使用 C 一样。

      enum Errors: Int {
          case transactionNotFound = 500
          case timeout = -1001
          case invalidState = 409
          case notFound = 404
          case unknown
      
          init(value: Int) {
              if let error = Errors(rawValue: value) {
                  self = error
              } else {
                  self = .unknown
              }
          }
      }
      
      Errors(value: 40) // .unknown
      Errors(value: 409) // .invalidState
      Errors(value: 500) // .transactionNotFound
      

      必须创建一个自定义初始化器,否则它是递归的。并且仍然有可能意外地使用 rawValue 初始化程序进行创建。

      然而这感觉更 Swifty,我删除了允许您使用关联值的 : Int 类型说明符,现在我们不做任何特殊处理的例外情况在 other 中处理:

      enum Errors2 {
          case transactionNotFound
          case timeout
          case invalidState
          case notFound
          case other(Int)
      
          init(rawValue: Int) {
              switch rawValue {
              case 500:
                  self = .transactionNotFound
              case -1001:
                  self = .timeout
              case 409:
                  self = .invalidState
              case 404:
                  self = .notFound
              default:
                  self = .other(rawValue)
              }
          }
      }
      
      Errors2(rawValue: 40) // .other(40)
      Errors2(rawValue: 409) // .invalidState
      Errors2(rawValue: 500) // .transactionNotFound
      Errors2(rawValue: -1001) // .timeout
      

      有了这个我可以得到一个“其他”错误的实际值,我可以使用 rawValue 所以它的行为很像一个基于 Int 的枚举。有一个 case 语句来映射名称,但从那时起,您可以使用名称而无需引用数字。

      【讨论】:

      • self = Errors(rawValue: value) ?? .unknown
      【解决方案4】:

      像这样:

      init() {
          self = .Cool
      }
      

      【讨论】:

      • 这是最干净的方式。 self 对于值类型是可变的。
      【解决方案5】:

      在 Swift 5.1 中,现在可以设置默认值。您的代码如下所示:

      enum PersonType {
        case cool(String = "cool")
        case nice(String = "rude")
        case soLazy(String = "so-lazy")
      }
      

      【讨论】:

        【解决方案6】:

        这个问题现在已经很老了,在 Swift 世界中已经发生了很多变化。对于 Swift 5,我建议使用以下方法,其中涉及为枚举创建一个新的初始化程序:

        public enum PersonType:String, ExpressibleByNilLiteral {
        
            case Cool = "cool"
            case Nice = "rude"
            case SoLazy = "so-lazy"
        
            public init(nilLiteral:()) {
                self = .SoLazy
            }
        
            public init!(_ optionalValue:RawValue?) {
                guard let rawValue = optionalValue,
                      let validValue = PersonType(rawValue:rawValue) else {
                    self = .SoLazy
                    return
                }
                self = validValue
            }
        
            public var description: String {
                switch self {
                case .Cool return "Cool Person"
                //... etc
                }
            }
        
            public var typeImage: String {
                switch self {
                case .Cool return "cool.png"
                //... etc
                }
            }
        }
        

        像这样使用它:

        self.personType = PersonType(personTypeKey)
        

        或者像这样:

        self.personType = nil
        

        在任何一种情况下,即使该值对于 PersonType 枚举无效或者它只是 nil,您也会得到一个设置为默认值 .SoLazy 的有效枚举

        这类似于此线程中的其他几种方法,但它不是列出所有可能的有效值(如果它们很多,可能会很笨拙),它使用多个 guard let = 语句来保证它的工作原理。

        【讨论】:

          【解决方案7】:

          试试这个方法。

          public enum PersonType:String {
          
              case Cool                       = "cool"
              case Nice                       = "rude"
              case SoLazy                     = "so-lazy"
          
              static let allKeys = [Cool.rawValue, Nice.rawValue, SoLazy.rawValue]
          }
          
          extension PersonType
          {
              func description(personTypeKey : String) -> String {
          
                  if PersonType.allKeys.contains(personTypeKey)
                  {
                      switch self {
                      case .Cool:
                          return "Cool person"
                      case .Nice:
                          return "Nice person"
                      case .SoLazy:
                          return "its so lazy person"
                      }
                  }
                  else
                  {
                      return "YourTextHere"
                  }
              }
          
              func typeImage(personTypeKey : String) -> String {
          
                  if PersonType.allKeys.contains(personTypeKey)
                  {
                      switch self {
                      case .Cool:
                          return "cool.png"
                      case .Nice:
                          return "img_nice.png"
                      case .SoLazy:
                          return "lazy.png"
                      }
                  }
                  else
                  {
                      return "YourImageHere"
                  }
              }
          }
          

          【讨论】:

          • 用你的方法如何使用未知键创建枚举
          • @iOSGeek 已更新答案,请检查。
          【解决方案8】:

          我想知道字典是否比枚举更适合这里:

          let dict = [
              "Cool": "cool",
              "Nice": "rude",
              "SoLazy": "so-lazy"
          ]
          
          let personType = "unknown"
          let personDescription = dict[personType] ?? "Unknown"
          

          更少的输入,更快的处理,更自然的默认大小写处理,更容易扩展。

          【讨论】:

          • 每种类型都有一个图像,也许以后还有一个var,所以字典不适合我的情况
          • 在这种情况下,您不会使用 [String: String] 字典,而是使用 [String: (String, String)]、[String: [String]] 或 [String: Custom Struct]跨度>
          【解决方案9】:

          你的情况:

          枚举的默认值: 我只是添加了一个default 计算属性, 或者包含一个自定义初始化。

          public enum PersonType:String {
          
              case Cool                       = "cool"
              case Nice                       = "rude"
              case SoLazy                     = "so-lazy"
          
              /// add a `default` computer property
              public static var `default`: PersonType {
                  return .SoLazy
              }
          
              /// add an customize init function 
              public init(person: String? = nil) {
                  if let person = person {
                      switch person {
                      case "cool": self = .Cool
                      case "rude": self = .Nice
                      case "so-lazy": self = .SoLazy
                      default: self = .SoLazy
                      }
                  } else {
                      self = .SoLazy
                  }
              }
          
              public var description: String {
                  switch self {
                  case .Cool:
                      return "Cool person"
                  case .Nice:
                      return "Nice person"
                  case .SoLazy:
                      return "its so lazy person"
                  }
              }
          
              public var typeImage: String {
                  switch self {
                  case .Cool:
                      return "cool.png"
                  case .Nice:
                      return "img_nice.png"
                  case .SoLazy:
                      return "lazy.png"
                  }
              }
          
          }
          

          使用方法:

          if let personType = PersonType(rawValue:personTypeKey ?? "") {
              self.personType = personType
          } else {
              self.personType = PersonType.default
          }
          

          或者

          if let personType = PersonType(rawValue:personTypeKey ?? "") {
              self.personType = personType
          } else {
              self.personType = PersonType()
          }
          

          具有关联值的枚举的默认值:

          public enum Gender {
              case man
              case woman
          }
          
          public enum PersonType {
          
              case cool(Gender)
              case nice(Gender)
              case soLazy(Gender)
          
              public static var `default`: PersonType {
                  return PersonType.make.soLazy()
              }
          
              public enum Builder {
                  public static func cool() -> PersonType {
                      return PersonType.cool(.woman)
                  }
                  public static func nice() -> PersonType {
                      return PersonType.nice(.woman)
                  }
                  public static func soLazy() -> PersonType {
                      return PersonType.soLazy(.woman)
                  }
              }
          
              public static var make: PersonType.Builder.Type {
                  return PersonType.Builder.self
              }
          
          
              public var description: String {
                  switch self {
                  case .cool(let gender):
                      switch gender {
                      case .man: return "Cool boy"
                      case .woman: return "Cool girl"
                      }
                  case .nice(let gender):
                      switch gender {
                      case .man: return "Nice boy"
                      case .woman: return "Nice girl"
                      }
                  case .soLazy(let gender):
                      switch gender {
                      case .man: return "its so lazy boy"
                      case .woman: return "its so lazy girl"
                      }
                  }
              }
          
              public var typeImage: String {
                  switch self {
                  case .cool(_):
                      return "cool.png"
                  case .nice(_):
                      return "img_nice.png"
                  case .soLazy(_):
                      return "lazy.png"
                  }
              }
          
          }
          

          使用方法:

          let onePersonType = PersonType.default
          let anotherPersonType = PersonType.make.soLazy()
          

          我在Ilya Puchka' blog 上找到的第二种情况解决方案。 在swift's proposal中也提到过。

          【讨论】:

            【解决方案10】:

            回答你的问题:

            public enum PersonType:String {
            
                case Cool                       = "cool"
                case Nice                       = "rude"
                case SoLazy                     = "so-lazy"
                static var `default`: PersonType { return .SoLazy }
            
                public init(rawValue: RawValue) {
                    switch rawValue {
                    case PersonType.Cool.rawValue: self = .Cool
                    case PersonType.Nice.rawValue: self = .Nice
                    case PersonType.SoLazy.rawValue: self = .SoLazy
                    default: self = .default
                    }
                }
            
                public var description: String {
                    switch self {
                    case .Cool:
                        return "Cool person"
                    case .Nice:
                        return "Nice person"
                    case .SoLazy:
                        return "its so lazy person"
                    }
                }
            
                public var typeImage: String {
                    switch self {
                    case .Cool:
                        return "cool.png"
                    case .Nice:
                        return "img_nice.png"
                    case .SoLazy:
                        return "lazy.png"
                    }
                }
            
            }
            

            现在因为没有默认值的可失败初始化器替换你的:

            if let personType = PersonType(rawValue:personTypeKey ?? "") {
               self.personType = personType
            }
            

            与:

            personType = PersonType(rawValue: personTypeKey)
            

            【讨论】:

              【解决方案11】:

              我推荐使用这种方法

              public enum Result {
                  case passed(hint: String)
                  case failed(message: String)
              
                  static let passed: Self = .passed(hint: "")
              }
              
              
              let res: Result = Result.passed
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2011-10-27
                • 1970-01-01
                • 2015-08-22
                • 2019-05-07
                • 2011-10-14
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多