Swift enum associated values - swift

I have API that have path and an int after it.
For example, /get/news/{id}.
For path endpoints i have enum like that:
enum Endpoints : String {
case news = "news"
}
Is there any convinient way to use associated values with it?
Something like :
case newsById(id: String) = "get/news/" + id

You can use this:
enum APIEndpoints {
case news(id: Int)
var path: String {
switch self {
case let .news(id):
return "/get/news/\(id)"
}
}
}
And use it like: APIEndpoints.news(id: 5).path

You can always add a function to the enum to get the URI:
enum Endpoints : String {
case news = "news"
func getUri(id: string) -> String {
return "get/\(self.rawValue)/\(id)"
}
}

you could try this:
enum Endpoints: String {
case news
func getNewsByStringId() -> String {
return "get/news/\(self.rawValue)"
}
}

Related

SOLVED - Swift Enum - Casting Nested Enums to String Enum to allow .rawValue

SOLVED
Thank you #New Dev and #Joakim Danielson for your help. I used #Joakim Danielson's answer to improve my code.
I have an extension method to assign accessibilityIdentifiers to views based on a given String Enum. I updated the method to directly accept String Enum Cases as a parameter, thus COMPLETELY eliminating the need for the AccessibilityId enum class as shown below, awesome!
Changes
Before:
.accessibility(identifier: .home(.clickButton))
// Simplified for StackOverflow.
// Imagine 20 more cases..
enum AccessibilityId {
case home(HomeId)
var rawValue: String {
switch self {
case .home(let id):
return id.rawValue
}
}
}
extension View {
func accessibility(identifier: AccessibilityId) -> ModifiedContent<Self, AccessibilityAttachmentModifier> {
self.accessibility(identifier: identifier.rawValue)
}
}
After:
.accessibility(identifier: HomeId.clickButton)
extension View {
func accessibility<T: RawRepresentable>(identifier: T) -> ModifiedContent<Self, AccessibilityAttachmentModifier> where T.RawValue == String {
self.accessibility(identifier: identifier.rawValue)
}
}
---------------------------------------------------------------
Original Question
What I have
enum Item {
case animal(AnimalId)
case vehicle(VehicleId)
case food(FoodId)
var rawValue: String {
switch self {
case .animal(let id):
return id.rawValue
case .vehicle(let id):
return id.rawValue
case .food(let id):
return id.rawValue
}
}
}
enum AnimalId: String {
case cat
case dog
}
// etc.
// Imagine more cases and more enums.
What I want
enum Item {
case animal(AnimalId)
case vehicle(VehicleId)
case food(FoodId)
var rawValue: String {
switch self {
case self as StringEnum:
return id.rawValue
default:
return ""
}
}
}
Usage
func test() {
foo(.animal(.cat))
foo(.vehicle(.plane))
foo(.food(.tacos))
}
func foo(_ item: Item) {
print(item.rawValue)
}
I am happy with the usage, but I'd like to reduce the amount of duplicate cases in the given switch statement. Notice how they all have return id.rawValue. The above is just an example, in reality I have around 30 cases.
My Question
Is there a way for me to catch all Nested String Enums in a single switch or let case to reduce the duplicate code I have to write without losing the intended usage?
Thank you for your efforts, I hope to find an improvement for my code!
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
You need something common between all these associated values, like a conformance to a shared protocol, e.g. protocol RawStringValue:
protocol RawStringValue {
var rawValue: String { get }
}
// String enums already conform without any extra implementation
extension AnimalId: RawStringValue {}
extension VehicleId: RawStringValue {}
extension FoodId: RawStringValue {}
Then you could create a switch self inside like so:
var rawValue: String {
switch self {
case .animal (let id as RawStringValue),
.vehicle (let id as RawStringValue),
.food (let id as RawStringValue):
return id.rawValue
}
}
That being said, enum with associated values isn't the most convenient type to work with, so be sure that it's the right choice.

How to create Enum for hardcoded string in swift?

I have some hardcoded string, based on that i have created switch case. But instead of string in switch case i am trying to create Enum for same. but i am not sure how to do that. I dont want to use default case.
Do i need to access with raw value or any other better way to do ?
enum screens: String {
case faq = "faq", contactus = "contactus", termncondi = "termncondi", dashoboard = "dashoboard"
}
func deepLink(text: String) -> String {
switch text {
case "faq":
return (FAQ.localized())
case "contactus":
return (Contactus.localized())
case "termncondi":
return (Term.localized())
case "dashoboard":
return (Dashboard.localized())
default:
return ""
}
}
You can simply define the enum and override the rawValue property like so:
enum Link {
case faq
case contact
...
var rawValue: String {
switch self {
case .faq:
return FAQ.localized()
case .contact:
return Contact.localized()
default:
return "Unknown case"
}
}
}
And get its rawValue.
let faqLink = Link.faq.rawValue
You can also perform a switch on an enum instance just like you do with a string.
In order to get hardcoded values do something like:
public extension String {
static func getScreens(name: DeepLink) -> String {
return name.rawValue
}
public enum DeepLink: String {
case faq = "faq"
case contactus = "contactus"
// and so on
}
}

Kotlin enum classes in Swift

I would like to use this Kotiln code in Swift, but I don't know how to get the best and clean solution:
enum class ProType(val gCode: String, val cCode: String) {
FUND("FN", "PP"),
STOCK("VA", "")
}
Technically #esemusa answer is right. But if you have more than ~5 values in enum, you end up with difficult to maintain giant switch statements for every property.
So for cases like that I prefer to do this:
struct ProTypeItem {
var gCode: String
var cCode: String
}
struct ProType {
static let fund = ProTypeItem(gCode: "FN", cCode: "PP")
static let stock = ProTypeItem(gCode: "VA", cCode: "")
}
And you use it simply as ProType.stock, ProType.fund.gCode etc
You can also make ProTypeItem Comparable, Equatable etc.
should be like this:
enum ProType {
case fund
case stock
var gCode: String {
switch self {
case .fund:
return "FN"
case .stock:
return "VA"
}
}
var cCode: String {
switch self {
case .fund:
return "PP"
case .stock:
return ""
}
}
}

Is there a way to make a function to accept any Enum types that have a rawValue of String?

One way I came up with is to make a protocol that other Enum must conform to.
protocol StringRepresentable
{
var rawValue: String { get }
}
struct Endpoint
{
enum User: String, StringRepresentable
{
case Login = "/user/login"
case Register = "/user/register"
}
enum Item: String, StringRepresentable
{
case Like = "/item/like"
case Buy = "/item/buy"
}
}
func urlString(endpoint: StringRepresentable) -> String
{
return "http://www.example.com\(endpoint.rawValue)"
}
let userLoginEndpoint = urlString(Endpoint.User.Login)
let buyItemEndpoint = urlString(Endpoint.Item.Buy)
Is there any other way that better than this?
Or is there a protocol, already provided something like this, that I missed?
There is already the RawRepresentable protocol which does what you want.
And you can extend based on whether RawValue == String

How should I implement Default Associated Values with Swift Enums?

Swift question is there a way of having an enum type with one case that can have an associated value.
I have an API that gives me available filters, it's unlikely but possible that the API will add additional filter types. So if the API sends an unknown filter type I want to keep that information associated with the enum.
Below are the different ideas I had about doing this.
My first two tries didn't compile. My third try just feels a bit clunky.
Does anyone have a better way of doing this? Do you think I just shouldn't use an enum for this problem?
typealias APIFilterIdentifier = String
/* Does Not Compile */
enum EnumTestAssociatedValeu: APIFilterIdentifier {
case Unknown(APIFilterIdentifier)
case Everyone = "everyone"
case Team = "myteam"
}
/* Does not compile */
enum EnumTestDefaultAssociatedValues: APIFilterIdentifier {
case Unknown(APIFilterIdentifier)
case Everyone(APIFilterIdentifier = "everyone")
case Team(APIFilterIdentifier = "myteam")
}
/* Compiles but is there a better way? */
enum EnumTestWithCustomInit {
case Unknown(APIFilterIdentifier)
case Everyone
case Team
init(filterIdentifier: APIFilterIdentifier) {
let everyone: APIFilterIdentifier = EnumTestWithCustomInit.everyoneFilterIdentifier
let team: APIFilterIdentifier = EnumTestWithCustomInit.teamFilterIdentifier
switch filterIdentifier {
case everyone:
self = .Everyone
case team:
self = .Team
default:
self = .Unknown(filterIdentifier)
}
}
func asIdentifer() -> APIFilterIdentifier {
switch self {
case .Everyone:
return EnumTestWithCustomInit.everyoneFilterIdentifier
case .Team:
return EnumTestWithCustomInit.teamFilterIdentifier
case .Unknown(let filterIdentifier):
return filterIdentifier
}
}
private static var everyoneFilterIdentifier: APIFilterIdentifier {
return "everyone"
}
private static var teamFilterIdentifier: APIFilterIdentifier {
return "myteam"
}
}
I know this is a bit old, but would this work for what you want?
typealias FilterIdentifier = String
enum DefaultAPIFilters: FilterIdentifier {
case Everyone = "everyone"
case Team = "team"
}
enum APIFilters {
case Default(DefaultAPIFilters)
case Custom(FilterIdentifier)
}
let everyoneFilter = APIFilters.Default(.Everyone)
let teamFilter = APIFilters.Default(.Team)
let clownFilter = APIFilters.Custom("clowns_only")
Extending Nathan Perry's response:
You can add a
var underlyingString: String {
return getUnderlyingString(self)
}
to the enum. Then define
func getUnderlyingString(apiFilter: APIFilters) -> String {
switch apiFilter {
case .Default(let defaultAPIFilter):
return defaultAPIFilter.rawValue
case .Custom(let custom):
return custom
}
}
According to this answer: Default value for Enum in Swift
I recommend using such an approach
public enum Result {
case passed(hint: String)
case failed(message: String)
static let passed: Self = .passed(hint: "")
}
let res: Result = Result.passed