Reputation: 30368
Ok, there's an existing question here on S/O with the following title:
Swift: Get Variable Actual Name as String
By it's name, it seems that's exactly what I want. However, looking at the accepted answer (and the other non-accepted ones), they are referring to key path manipulation, which isn't what I'm after. (i.e. This is not a duplicate!)
In my case, I want the name of one variable to be stored in a second variable of type string.
In C#, this is trivial using nameof
, like so...
int someVar = 3
string varName = nameof(someVar)
// 'varName' now holds the string value "someVar"
Note:
nameof()
executes at compile-time, not run-time so no reflection or anything else is needed. The compiler simply subs in the name of the variable as if someone manually typed its name as a string constant.
It's pretty handy when you, for instance, want to define a query object where your member names match the query parameters passed in a URL.
Here's a pseudo-code example (i.e. this clearly won't compile, but shows what I'm after.)
Also, please don't focus on the URL aspects of this. This is definitely *bad code*. In real code I'd use URLComponents
, not string-append a URL like I'm doing here. Again, this is *only* illustrating my question, not building URLs.
struct queryObject{
let userName : String
let highScore : Int
var getUrl:String{
return "www.ScoreTracker.com/postScore?\(nameof(userName))=\(userName)&\(nameof(highScore))=\(highScore)"
}
}
Here's how you'd use it and what it would return:
let queryObject = QueryObject(userName:"Maverick", highScore:123456)
let urlString = queryObject.getUrl
The return value would be:
www.ScoreTracker.com/postScore?userName=Maverick&highScore=123456
The advantages of having access to a string representation of a variable, instead of using string constants are many:
For instance, say the API changed the query param from userName
to userId
, all one would have to do is refactor the variable name and the output would update accordingly without having to manually touch any strings.
So, can this be done in Swift? Can you get the actual variable name and store it in a second variable?
Upvotes: 13
Views: 1919
Reputation: 101
If you are only dealing with URLs, it is recommended to use URLComponents, which is better.
model:
struct QueryObject{
var params = [String: String]()
var getUrl: String{
let result = "www.ScoreTracker.com/postScore"
guard var url = URL(string: result) else { return result}
url.appendQueryParameters(params)
return url.absoluteString
}
init(params: [String: String]) {
self.params = params
}
}
then:
let params = ["userName": "Maverick", "highScore": "123456"]
let queryObject = QueryObject(params: params)
let urlString = queryObject.getUrl
DDLog(urlString) //www.ScoreTracker.com/postScore?userName=Maverick&highScore=123456
Github link
Upvotes: 1
Reputation: 1866
Yes you can. I've used this as a solution for the next scenario: When I print an object/struct in the console, I like to see the vars names along with associated values:
extension CustomStringConvertible {
var description: String {
var description = "\n ***** \(type(of: self)) *****\n"
let mirrorS = Mirror(reflecting: self)
for child in mirrorS.children {
if let propertyName = child.label {
description += " \(getSpaces(forWord: propertyName))\(propertyName): \(child.value)\n"
}
}
return description
}
}
And to use this, let's have as an example the following struct:
public struct FavoriteApp: Codable, CustomStringConvertible, Hashable {
let appId: String
let appName: String
let bundleId: String
let image: NSImage
let isMacApp: Bool
let rating: String
let screenshotUrls: [String]
let sellerName: String
let sellerUrl: String
let releaseDate: String
let genres: String
let latestVersion: String
}
let anApp:FavoriteApp = getTheAppInfoFromServer()
print(anApp)
// This will print into console:
// ***** FavoriteApp *****
// appId: 1438547269
// appName: Dynamic wallpaper
// bundleId: com.minglebit.DynamicWallpaper
// image: -not visible- (but is there, trust me :))
// isMacApp true
// rating: 0
//
// screenshotUrls: https://is1-ssl.mzstatic.com/image/thumb/Purple128/v4/5c/08/b8/5c08b824-12eb-e0b6-22fb-0e234f396b9e/pr_source.jpg/800x500bb.jpg
// https://is1-ssl.mzstatic.com/image/thumb/Purple128/v4/f3/34/0e/f3340e21-714c-0a17-4437-73ba1828cbba/pr_source.jpg/800x500bb.jpg
// sellerName: MingleBit SRL
// sellerUrl: https://minglebit.com/products/dynamicwallpaper.php
// releaseDate: 2018-10-18T14:59:47Z
// genres: Entertainment, Lifestyle
// latestVersion: 2.3
So, to concentrate the answer, use Mirror(reflecting: object)
to get what you want.
Upvotes: 1