Is there a way to make a function to accept any Enum types that have a rawValue of String?
There is already the RawRepresentable
protocol which does what you want.
And you can extend based on whether RawValue == String
How to write a generic function to convert any enum value to its string representation?
You need to add a constraint to the 2nd parameter : T[keyof T]
instead of number
.
Also note that the key of your enum
is of type string
.
function enumToString<T extends { [name: string]: number | string }>(myenum: T, myenumvalue: T[keyof T]) {
return myenum[myenumvalue];
}
Playground
How do you declare an argument of type 'enum' (i.e. it can take any enum)?
Following Wain's suggestion, you can write something like this:
enum FirstEnum: String
{
case
A,
B,
C
}
enum SecondEnum: String
{
case
D,
E,
F
}
//create a protocol
public protocol StringKeyEnum {
var rawValue: String {get}
}
//make the enumeration(s) conform to it
extension FirstEnum: StringKeyEnum {}
extension SecondEnum: StringKeyEnum {}
var myDictionary: [String: AnyObject] = [:]
//use it in your interface definitions
public func storeValue(key: StringKeyEnum, value: AnyObject)
{
myDictionary[key.rawValue] = value //<-- Uses the rawValue of enum as a key
}
let someItem = ""
storeValue(FirstEnum.A, value: someItem) // Using the first enum type
storeValue(SecondEnum.D, value: someItem) // Using the second enum type
storeValue("Sam", value: someItem) // Won't compile since 'Sam' is not a StringKeyEnum
How to enumerate an enum with String type?
Swift 4.2+
Starting with Swift 4.2 (with Xcode 10), just add protocol conformance to CaseIterable
to benefit from allCases
. To add this protocol conformance, you simply need to write somewhere:
extension Suit: CaseIterable {}
If the enum is your own, you may specify the conformance directly in the declaration:
enum Suit: String, CaseIterable { case spades = "♠"; case hearts = "♥"; case diamonds = "♦"; case clubs = "♣" }
Then the following code will print all possible values:
Suit.allCases.forEach {
print($0.rawValue)
}
Compatibility with earlier Swift versions (3.x and 4.x)
If you need to support Swift 3.x or 4.0, you may mimic the Swift 4.2 implementation by adding the following code:
#if !swift(>=4.2)
public protocol CaseIterable {
associatedtype AllCases: Collection where AllCases.Element == Self
static var allCases: AllCases { get }
}
extension CaseIterable where Self: Hashable {
static var allCases: [Self] {
return [Self](AnySequence { () -> AnyIterator<Self> in
var raw = 0
var first: Self?
return AnyIterator {
let current = withUnsafeBytes(of: &raw) { $0.load(as: Self.self) }
if raw == 0 {
first = current
} else if current == first {
return nil
}
raw += 1
return current
}
})
}
}
#endif
SOLVED - Swift Enum - Casting Nested Enums to String Enum to allow .rawValue
Here is a solution that is not based on Item being an enum but instead a generic struct
struct Item<T: RawRepresentable> where T.RawValue == String {
let thing: T
var rawValue: String {
thing.rawValue
}
}
With this solution you don't need to change your other enums.
Example
let item1 = Item(thing: AnimalId.cat)
let item2 = Item(thing: VehicleId.car)
print(item1.rawValue, item2.rawValue)
outputs
cat car
generics type constraining for raw value in enums
If the intention is that the function accepts any enumeration type whose raw value is a string then this can be achieved with
func someFunc1<T: CaseIterable & RawRepresentable>(ofType: T.Type) where T.RawValue == String {
for aCase in T.allCases {
let someString: String = aCase.rawValue
print(someString)
}
}
someFunc1(ofType: SomeEnum.self)
// Hello
// How are you?
How to get enum from raw value in Swift?
Too complicated, just assign the raw values directly to the cases
enum TestEnum: String {
case Name = "Name"
case Gender = "Gender"
case Birth = "Birth Day"
}
let name = TestEnum(rawValue: "Name")! //Name
let gender = TestEnum(rawValue: "Gender")! //Gender
let birth = TestEnum(rawValue: "Birth Day")! //Birth
If the case name matches the raw value you can even omit it
enum TestEnum: String {
case Name, Gender, Birth = "Birth Day"
}
In Swift 3+ all enum cases are lowercased
Can a Swift enum have a function/closure as a raw value?
It's not as straight forward, but you could use OptionSet
, see this page:
Unlike enumerations, option sets provide a nonfailable init(rawValue:) initializer to convert from a raw value, because option sets don’t have an enumerated list of all possible cases. Option set values have a one-to-one correspondence with their associated raw values.
Could be something like this:
func doSomething() {}
func doSomethingElse() {}
struct MyClosures: OptionSet {
static let closureOne = MyClosures(rawValue: doSomething)
static let closureTwo = MyClosures(rawValue: doSomethingElse)
let rawValue: () -> Void
init(rawValue: @escaping () -> Void) {
self.rawValue = rawValue
}
init() {
rawValue = {}
}
mutating func formUnion(_ other: __owned MyClosures) {
// whatever makes sense for your case
}
mutating func formIntersection(_ other: MyClosures) {
// whatever makes sense for your case
}
mutating func formSymmetricDifference(_ other: __owned MyClosures) {
// whatever makes sense for your case
}
static func == (lhs: MyClosures, rhs: MyClosures) -> Bool {
// whatever makes sense for your case
return false
}
}
And so you can use it as:
let myClosures: MyClosures = [ .closureOne, .closureTwo ]
HOWEVER looking at your explanation in the comment:
So I'm trying to find the most efficient way to run a function given the state of a variable.
I think what you actually want is some sort of state machine. Some examples are available here and here
Related Topics
Programmatically Place Partial Image Over Another in UIview Using Swift 3
How to Compare Two Dates (Nsdate) in Swift 3 and Get The Days Between Them
Parametrized Unit Tests in Swift
How to Add More Cases for Enum in Swift
Debug View Hierarchy Does Not Render UI
"Ambiguous Reference to Member Map" When Attempting to Append/Replace Array Element
Swift Override Static Method Compile Error
"This Class Is Not Key Value Coding-Compliant" Using Coreimage
Access Class Property from Instance
Ambiguous Use of 'Filter' When Converting Project to Swift 4
Protocol Associated Type Typealias Assignment Compile Error
Tableview.Cellforrowatindexpath(Indexpath) Return Nil
No Exact Matches in Call to Instance Method Error Message in Swift
Can't Upload .Ipa from Xcode 8, "The Info.Plist Indicates a iOS App, But Submitting a Pkg or Mpkg."