Getting string from syntax of new Swift 4 syntax?

How can you get a string value from the Swift 4 smart keypaths syntax (e.g. \Foo.bar )? At this moment, I still wonder if it got complicated.

I like the idea of ​​type information associated with a smart key. But not all APIs and third parties still exist.

There is an old way of getting a string for a property name with checking compile time using #keyPath() . With Swift 4, to use #keyPath() you must declare the property as @objc , which I would rather avoid.

+26
reflection ios swift swift4 key-value-coding
source share
5 answers

For Objective-C properties in Objective-C classes, you can use the _kvcKeyPathString property to get it.

However, Swift paths may not have line equivalents. The key to Swift's key paths is that they do not require the names of the fields that should be included in the executable. It is possible that the key path can be represented as a sequence of field offsets to receive or close to call an object.

Of course, this directly contradicts your own goal - to avoid declaring @objc properties. I believe that there is no built-in tool to accomplish what you want to do.

+16
source share

Short answer: you cannot. The KeyPath abstraction KeyPath intended to encapsulate a potentially nested property key path from a given root type. Thus, exporting a single String value may not make sense in the general case.

For example, should a hypothetical exported string be interpreted as a property of the root type or a member of one of its properties? At least an array of strings should be exported to solve such scenarios ...

Workaround for each type . Having said that, given that KeyPath conforms to the Equatable protocol, you can independently create your own solution for each type. For example:

 struct Auth { var email: String var password: String } struct User { var name: String var auth: Auth } 

provide an extension for User main paths:

 extension PartialKeyPath where Root == User { var stringValue: String { switch self { case \User.name: return "name" case \User.auth: return "auth" case \User.auth.email: return "auth.email" case \User.auth.password: return "auth.password" default: fatalError("Unexpected key path") } } 

using:

 let name: KeyPath<User, String> = \User.name let email: KeyPath<User, String> = \User.auth.email print(name.stringValue) /* name */ print(email.stringValue) /* auth.email */ 

I would not recommend this solution for production code, given the somewhat high level of service, etc. But since you were curious that this at least gives you a way forward;)

+23
source share

A bit late for the party, but I came across a way to get the key path string from NSObject subclasses at least:

 NSExpression(forKeyPath: \UIView.bounds).keyPath 
+20
source share

This works as a Swift 4 extension:

 extension AnyKeyPath { /// Returns key path represented as a string var asString: String? { return _kvcKeyPathString?.description } } 

Using:

 (\UIView.bounds).asString // or let keyPath = \UIView.bounds keyPath.asString 
0
source share

Extending @Andy Heard's answer, we can extend KeyPath to get a computed property, for example:

 extension KeyPath where Root: NSObject { var toString: String { return NSExpression(forKeyPath: self).keyPath } } // Usage let stringValue = (\Foo.bar).toString print(stringValue) // prints "bar" 
0
source share

All Articles