0

How do we print variable name in swift? It's similar to what this question discusses Get a Swift Variable's Actual Name as String I can't figure out from above QA how to print it in swift for my need as described below

struct API {
    static let apiEndPoint = "example.com/profile?"
    static let apiEndPoint1 = "example.com/user?"
 }

doSomething(endPoint: API.apiEndPoint)
doSomething(endPoint: API.apiEndPoint1)

func doSomething(endPoint: String) {
    // print the variable name which should be apiEndPoint or endPoint1
} 
8
  • 1
    print("apiEndPoint")? Commented Jan 30, 2020 at 19:16
  • 1
    You should use a dictionary instead of a variable, if you don't want to hardcode variable names in print calls. Commented Jan 30, 2020 at 19:17
  • 6
    There's no way to do what you've literally asked for, but there are several approaches to doing similar things. What are you trying to acheve? Commented Jan 30, 2020 at 19:17
  • I've updated my question. I said I just want to print the variable name. Commented Jan 30, 2020 at 19:21
  • 1
    No. From the point of view of your doSomething method, all it sees is the value of its endPoint parameter. Where that came from, a variable, a constant, a function call, whatever, is not visible to it. Commented Jan 30, 2020 at 19:36

3 Answers 3

5

You could change your struct to an enum

enum API: String {
    case apiEndPoint = "example.com/profile?"
    case apiEndPoint1 = "example.com/user?"
 }


func doSomething(endPoint: API) {
    print("\(endPoint): \(endPoint.rawValue)")
}

Example

doSomething(endPoint: .apiEndPoint)

apiEndPoint: example.com/profile?

Sign up to request clarification or add additional context in comments.

3 Comments

You are spot on but for me changing struct to enum will require a lot of code changes.
@Raymond Maybe so but an enum could give you code that is easier to read and more type safe but of course I have no idea how much work it would be
@Raymond More code changes than any other method? This is exactly the sort of thing enums are meant for, anything else is just making it needlessly complicated.
2

You could use Mirror for reflection and do something silly like this:

struct API {
    let apiEndPoint = "example.com/profile?"
    let apiEndPoint1 = "example.com/user?"
}

func doSomething(api: API, endPoint: String) {
    let mirror = Mirror(reflecting: api)

    for child in mirror.children {
        if (child.value as? String) == endPoint {
            print(child.label!) // will print apiEndPoint
        }
    }
}

let api = API()

doSomething(api: api, endPoint: api.apiEndPoint)
doSomething(api: api, endPoint: api.apiEndPoint1)

But I would never recommend doing something like this, and using an enum like the other answer suggested is probably the way to go.

7 Comments

Yes I've seen this solution but it's not practical as I've hundreds of endpoints and I'll end up writing hundreds of if else conditions.
@Raymond don't know why this would make you need 100s of if/else's - it will work for any number of endpoints with no need for extra ifs
Sorry I missed it. Yes you are right. However it's not working for me. Please note that I'm not passing api to function, I'm only passing endPoint. I tired by doing let mirror = Mirror(reflecting: API()) but it didn't work, control doesn't go inside the if condition.
@Raymond yeah, I had to add api as a parameter if you wanted it to work right, which is another reason I would suggest an enum instead since it is much cleaner. That said if the endpoints are constant let values that never change, I don't see why let mirror = Mirror(reflecting: API()) would not work, it works for me in my playground.
@Raymond Is mirror.children empty? Any chance your API let's are static?
|
1

I like Quinn's approach, but I believe it can be done more simply:

struct API {
    let apiEndPoint = "example.com/profile?"
    let apiEndPoint1 = "example.com/user?"

    func name(for string: String) -> String? {
        Mirror(reflecting: self).children
            .first { $0.value as? String == string }?.label
    }
}

func doSomething(endPoint: String) {
    print(API().name(for: endPoint)!)
}

let api = API()

doSomething(endPoint: api.apiEndPoint) // apiEndPoint
doSomething(endPoint: api.apiEndPoint1) // apiEndPoint1

3 Comments

It crashes on print(API().name(for: endPoint)!). Thread 12: Fatal error: Unexpectedly found nil while unwrapping an Optional value. Please note that I've static variables in structure. Also I don't use api = API() to pass api value in the function. I directly pass API.endPoint as I've written in question.
@Raymond it is because your variables are static, static variables don't appear in reflection so it is finding nothing and returning null
Agreed; this is likely not solvable for static properties or globals without adding some piece of metadata somewhere (creating a lookup Dictionary or creating a struct with the name and the path, for example).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.