【问题标题】:Swift enum getting value of Int Enum using String valueSwift枚举使用String值获取Int Enum的值
【发布时间】:2019-09-04 12:53:30
【问题描述】:

我有一个原始值是 Int 的枚举。我知道如何获得原始价值。但是我正在通过 web 服务访问数据,并且 Enum 的数据以字符串值的形式出现。

让我给你看我的 Enum,然后我们将讨论需要转换为 Enum 的数据,然后获取原始值。

我的枚举:

enum ReportStatus : Int {
case None = 0
case Received = 2
case Forward = 9
case Reporting = 14
case Completed = 50
}

我从网络服务获得的数据正在向我发送价值 像这样的字符串

var valueToCompareWithEnum = "Forward"

我想要什么:

我想匹配那个字符串值并得到结果 int 值。 例如,当我收到“转发”时,我必须将其转换为枚举 并获得 9 Int 值。

我知道我可以为它制作开关盒,但我想知道它是否可以用更干净的方式处理.....

提前谢谢请帮忙。

【问题讨论】:

    标签: swift


    【解决方案1】:

    您可以让您的枚举实现CaseIterable,然后使用Array.first(where:)将您的字符串与每个枚举案例的字符串表示进行比较

    enum ReportStatus : Int, CaseIterable {
        case None = 0
        case Received = 2
        case Forward = 9
        case Reporting = 14
        case Completed = 50
    
        static func translate(_ string: String) -> Int? {
            return ReportStatus.allCases.first(where: {string == "\($0)"})?.rawValue
        }
    }
    

    这里的变体是一个全局通用函数,它做同样的事情,但它返回枚举大小写而不是原始值。

    func translate<T: CaseIterable>(_ string: String, forEnum: T.Type) -> T? {
        return forEnum.allCases.first(where: {string == "\($0)"})
    }
    

    用法

    if let item = translate(valueToCompareWithEnum, forEnum: ReportStatus.self) {
        print(item.rawValue)
    }
    

    【讨论】:

      【解决方案2】:

      你可以这样编码;

      enum ReportStatus : Int {
          case None = 0
          case Received = 2
          case Forward = 9
          case Reporting = 14
          case Completed = 50
      
          static func getRawValue(from value : String) -> Int {
              switch value {
              case "Forward":
                  return self.Forward.rawValue
              case "Received":
                  return self.Received.rawValue
              case "Reporting":
                  return self.Reporting.rawValue
              case "Completed":
                  return self.Completed.rawValue
              default:
                  return self.None.rawValue
              }
          }
      
      }
      
      
      var valueToCompareWithEnum = "Forward"
      
      let myVal = ReportStatus.getRawValue(from: valueToCompareWithEnum)
      
      print(myVal) // 9
      

      【讨论】:

      • 除此之外没有干净的方法吗?
      • @A.s.ALI 我猜.. 是的。
      • Apple 总是不赞成在方法中使用“get”这个词。 Swift 是否改变了这一点,或者它只适用于属性?
      • @trojanfoe 我总是在我的方法中使用 get (包括 obj-c 和 swift),而且我从来没有遇到过苹果方面的任何问题。如果您可以提供相关链接,那将更好地给您答案。我认为 Apple 在这一点上没有任何问题。
      • @dahiya_boy 它内置在 Objective-C 中,例如,如果您声明一个属性 @property (readonly) Thing* thing;,您可以通过提供 - (Thing*)thing { ... } 来实现它。这不适用于- (Thing*)getThing { ... }。不过我不知道 Swift。
      【解决方案3】:

      由于您是从服务器接收这些字符串,我假设您的意思是您正在接收以 JSON 编码的它们。如果是这样,那么您可能希望它们是可解码的。在这种情况下,您可以实现自定义解码器。

      在我展示之前,我将重命名你的枚举 case 以匹配 Swift 风格,这是一个小写字母。我这样做是为了让问题稍微难一些,并展示更多你可以使用的技术。

      enum ReportStatus : Int {
          case none = 0
          case received = 2
          case forward = 9
          case reporting = 14
          case completed = 50
      }
      

      这是最直接的方法:

      extension ReportStatus: Decodable {
          init(from decoder: Decoder) throws {
              let container = try decoder.singleValueContainer()
              let stringValue = try container.decode(String.self)
      
              switch stringValue {
              case "None": self = .none
              case "Received": self = .received
              case "Forward": self = .forward
              case "Reporting": self = .reporting
              case "Completed": self = .completed
              default:
                  throw DecodingError
                      .valueNotFound(Self.self,
                                     .init(codingPath: decoder.codingPath,
                                           debugDescription: "Unknown value for report status: \(stringValue)"))
      
              }
          }
      }
      

      这是一个非常好的技术,但由于我们的案例名称确实与服务器的密钥非常匹配(只是不完美),我们可以通过小写密钥来解决这个问题:

      enum ReportStatus : Int, CaseIterable { // Note CaseIterable
          case none = 0
          case received = 2
          case forward = 9
          case reporting = 14
          case completed = 50
      }
      
      extension ReportStatus: Decodable {
          init(from decoder: Decoder) throws {
              let container = try decoder.singleValueContainer()
              let stringValue = try container.decode(String.self)
      
              guard let value = Self.allCases.first(where: { String(describing: $0) == stringValue.lowercased() })
                  else { throw DecodingError
                      .valueNotFound(Self.self,
                                     .init(codingPath: decoder.codingPath,
                                           debugDescription: "Unknown value for report status: \(stringValue)"))
              }
              self = value
      
          }
      }
      

      【讨论】:

        【解决方案4】:

        我建议您将 Int enum 切换为 String 以使其更易于解析并添加一个字段以获取每种情况的 int 值:

        enum ReportStatus: String {
        
            case none = "None"
            case received = "Received" 
            case forward = "Forward"
            case reporting = "Reporting"
            case completed = "Completed"
        
            var intValue: Int {
              switch self {
                case .none      : return 0 
                case .received  : return 2 
                case .forward   : return 9
                case .reporting : return 14
                case .completed : return 50
              }
           }
        }
        
        
        let valueToCompareWithEnum = "Forward"
        
        if let myVal = ReportStatus(rawValue: valueToCompareWithEnum) {
            print(myVal.intValue) // 9
        }
        

        因为来自网络的数据是字符串格式,所以建议将其解析为字符串枚举大小写,然后在需要的地方使用您自己的 Int 值。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-08-20
          • 2011-06-02
          • 2012-06-18
          • 2014-02-02
          • 1970-01-01
          • 1970-01-01
          • 2010-10-30
          相关资源
          最近更新 更多