Enumeration of non-literal values ​​in Swift

Is there a way to match a non-literal meaning, such as a set of words to list? The following code produces Raw value for enum must be literal .

 enum FileType { case VIDEO = ["name": "Video", "contentTypeMatcher": "video/"] case IMAGE = ["name": "Image", "contentTypeMatcher": "image/"] case AUDIO = ["name": "Audio", "contentTypeMatcher": "aduio/"] case PDF = ["name": "PDF", "contentTypeMatcher":"application/pdf"] case TEXT = ["name": "Text", "contentTypeMatcher": "text/"] case FOLDER= ["name": "Folder", "contentTypeMatcher" :"application/x-directory"] case PLAIN = ["name": "Plain", "contentTypeMatcher": ""] } 

Same thing when I use tuples:

 enum FileType { case VIDEO = (name: "Video", contentTypeMatcher: "video/") case IMAGE = (name: "Image", contentTypeMatcher: "image/") case AUDIO = (name: "Audio", contentTypeMatcher: "aduio/") case PDF = (name: "PDF", contentTypeMatcher:"application/pdf") case TEXT = (name: "Text", contentTypeMatcher: "text/") case FOLDER = (name: "Folder", contentTypeMatcher :"application/x-directory") case PLAIN = (name: "Plain", contentTypeMatcher: "") } 
+8
enums swift
source share
2 answers

The language reference, speaking of the Enumeration Declaration , states that:

the raw-value type must conform to the Equatable protocol and one of the following convertible text protocols: IntegerLiteralConvertible for whole literals, FloatingPointLiteralConvertible for floating point literals, StringLiteralConvertible for string literals containing any number of characters, and ExtendedGraphemeClusterLiteralConvertible for only one literals.

Thus, literals can be used as initial values.

A possible workaround is to present the dictionary as a string - for example, you can separate the elements with commas and the key of the value with a colon:

 enum FileType : String { case VIDEO = "name:Video,contentTypeMatcher:video/" case IMAGE = "name:Image,contentTypeMatcher:image/" ... } 

Then, using the computed property (or, if you want, the method), restore the dictionary:

 var dictValue: [String : String] { var dict = [String : String]() var elements = self.rawValue.componentsSeparatedByString(",") for element in elements { var parts = element.componentsSeparatedByString(":") if parts.count == 2 { dict[parts[0]] = parts[1] } } return dict } 
+4
source share

@ Antonio gives a workaround, but does not answer the actual question.

Define your listing.

 enum FileType { case Image, Video } 

Give cases non-literal values, regardless of the type you want, with the RawRepresentable protocol. Do this with the enum extension to have cleaner code.

 extension FileType: RawRepresentable { typealias Tuple = (name: String, contentTypeMatcher: String) private static let allCases = [FileType.Image, .Video] // MARK: RawRepresentable typealias RawValue = Tuple init?(rawValue: Tuple) { guard let c = { () -> FileType? in for iCase in FileType.allCases { if rawValue == iCase.rawValue { return iCase } } return nil }() else { return nil } self = c } var rawValue: Tuple { switch self { case .Image: return Tuple("Image", "image/") case .Video: return Tuple("Video", "video/") } } } 

To be able to map Tuple in the switch, implement the pattern matching operator.

 private func ~= (lhs: FileType.Tuple, rhs: FileType.Tuple) -> Bool { return lhs.contentTypeMatcher == rhs.contentTypeMatcher && lhs.name == rhs.name } 

And here it is ...

 let a = FileType.Image print(a.rawValue.name) // "Image" let b = FileType(rawValue: a.rawValue)! print(a == b) // "true" print(b.rawValue.contentTypeMatcher) // "image/" 

Say I answered a question without interrogation. Now ... Enums (at least in Swift) are for unique occasions. The caveat about this workaround is that you can (I hope by chance) stick with the same rawValue for more cases. Usually your code code smells to me. If you (for a very reasonable reason) need to create a new enum value from a tuple, consider a redesign. If you want to go with this workaround, I suggest (depending on the project) to implement some verification if all the original case values ​​are unique. If not, consider this:

 enum FileType { case Video, Image var name: String { switch self { case .Image: return "Image" case .Video: return "Video" } var contentTypeMatcher: String { switch self { case .Image: return "image/" case .Video: return "video/" } } 
+4
source share

All Articles