MatterGoal
MatterGoal

Reputation: 16430

Enum of tuples in Swift

Is this possible to create a enum of Tuples in Swift?

I'd like to build something like:

enum ErrorCode: (Int, String) {
    case Generic_Error = (0, "Unknown")
    case DB_Error = (909, "Database")
}

But it doesn't compile...

'ErrorCode' declares raw type '(Int, String)', but does not conform to RawRepresentable and conformance could not be synthesized

Raw type '(Int, String)' is not expressible by a string, integer, or floating-point literal

RawRepresentable conformance cannot be synthesized because raw type '(Int, String)' is not Equatable

Is there a way to obtain a similar result?

Upvotes: 73

Views: 29446

Answers (10)

RichWalt
RichWalt

Reputation: 522

This is what I did in a similar situation. Use an associated data enum, with default values (you can even name the values in the tuple if you like). Then add a simple function that returns the tuple based on self.

enum ErrorCode {
    case Generic_Error( code: Int = 0, desc: String = "Unknown")
    case DB_Error( code: Int = 909, desc: String = "Database")


    func getCodeDescription() -> (Int, String) {
        switch self {
            case let .Generic_Error(code, desc): return (code, desc)
            case let .DB_Error(code, desc):  return(code, desc)
        }
    }
}

Later

var errorCode: Int
var errorDesc: String

let myError: ErrorCode = .DB_Error() // let it take the default values 
(errorCode, errorDesc) = myError.getCodeDescription()

Upvotes: 0

atulkhatri
atulkhatri

Reputation: 11343

I think I would change your code to something like this:

enum ErrorCode {
    case generic, db

    var message: String {
        switch self {
        case .generic:
            return "Unknown"
        case .db:
            return "Database"
        }
    }
    var code: Int {
        switch self {
        case .generic:
            return 0
        case .db:
            return 909
        }
    }
}

I feel this would make it much more easier to use like so:

let error = ErrorCode.generic
print("Error Code: \(error.code), Message: \(error.message)")

Upvotes: 3

rusito23
rusito23

Reputation: 1003

My solution to keep the enum, was to create the get method for the rawValue var:

enum LoadingType {
  case poster
  case movie
  case refresh

  var rawValue: (file: String, anim: String) {
    get {
      switch self {
      case .movie:
        return ("poster_loading", "LoadingView")
      case .poster:
        return ("loading", "LoadingView")
      case .refresh:
        return ("loading", "RefreshView")
      }
    }
  }
}

With this code, you can even call each of your Tuple elements by a name:

self.type.rawValue.file

Upvotes: 4

dr OX
dr OX

Reputation: 4759

enum ErrorCode {
    case Generic_Error
    case DB_Error

    public var code:Int{
        switch self {
        case .Generic_Error: return 0
        case .DB_Error: return 909
        }
    }

    public var name:String{
        switch self {
        case .Generic_Error: return "Unknown"
        case .DB_Error: return "Database"
        }
    }
}

using:

let err:ErrorCode = .Generic_Error
print(err.code)   //0
print(err.name)   //Unknown

Upvotes: 2

Au Ris
Au Ris

Reputation: 4669

Create your enum and add a var of tuple type (String, String).

enum SomeType {
    case type1
    case type2
    case type3

    var typeNameAndDescription: (name: String, description: String) {
       switch self {
       case .type1:
            return ("type1 name", "type1 description")
        case .type2:
            return ("type2 name", "type2 description")
        case .type3:
            return ("type3 name", "type3 description")
       }
    }
}

and later:

let myType = SomeType.type1
let typeName = myType.typeNameAndDescription.name
let typeDescription = myType.typeNameAndDescription.description

Upvotes: 18

djtech42
djtech42

Reputation: 726

You can conform to RawRepresentable and use (Int, String) as the Self.RawValue associated type.

enum ErrorCode: RawRepresentable {
    case Generic_Error
    case DB_Error

    var rawValue: (Int, String) {
        switch self {
        case .Generic_Error: return (0, "Unknown")
        case .DB_Error: return (909, "Database")
        }
    }

    init?(rawValue: (Int, String)) {
        switch rawValue {
        case (0, "Unknown"): self = .Generic_Error
        case (909, "Database"): self = .DB_Error
        default: return nil
        }
    }
}

Upvotes: 53

mattt
mattt

Reputation: 19544

Swift enumerations cannot have Tuples as a raw value type.

Alternative approaches include storing the code and deriving a description from that:

enum ErrorCode: Int, CustomStringConvertible {
    case Generic = 0
    case DB = 909

    var description: String {
        switch self {
        case .Generic:
            return "Unknown"
        case .DB:
            return "Database"
        }
    }
}

...or storing associated values for code and description in the enumeration cases themselves:

enum Error {
    case Generic(Int, String)
    case DB(Int, String)
}

If you're just looking for constant values, @matt's suggestion of organizing them within a struct would work, too.

Upvotes: 59

holex
holex

Reputation: 24031

you can do such thing, maybe:

enum ErrorCode {
    case Generic_Error
    case DB_Error

    func values() -> (code: Int!, description: String?)! {
        switch self {
        case .Generic_Error:
            return (0, "Unknown")
        case .DB_Error:
            return (909, "Database")
        }
    }
}

and you can do such thing later:

let errorCode: ErrorCode = ErrorCode.Generic_Error;
if (errorCode.values().code == 0) {
    // do the business here...
}

Upvotes: 20

matt
matt

Reputation: 535880

It depends what you mean by "similar". What I do is use a Struct with static constant properties:

struct Trouble {
    static let Generic_Error = (0, "Unknown")
    static let DB_Error = (909, "Database")
}

Now things like Trouble.Generic_Error are usable throughout your code.

Upvotes: 49

Related Questions