Getting string from Swift 4 new key path syntax?

前端 未结 4 1944
别那么骄傲
别那么骄傲 2021-02-01 14:33

How can you get a string value from Swift 4 smart keypaths syntax (e.g., \\Foo.bar)? At this point I\'m curious about any way at all, does not matter if it

相关标签:
4条回答
  • 2021-02-01 14:53

    Expanding on @Andy Heard's answer we could extend KeyPath to have a computed property, like this:

    extension KeyPath where Root: NSObject {
        var stringValue: String {
            NSExpression(forKeyPath: self).keyPath
        }
    }
    
    // Usage
    let stringValue = (\Foo.bar).stringValue
    print(stringValue) // prints "bar"
    
    
    0 讨论(0)
  • 2021-02-01 14:54

    Short answer: you can't. The KeyPath abstraction is designed to encapsulate a potentially nested property key path from a given root type. As such, exporting a single String value might not make sense in the general case.

    For instance, should the hypothetically exported string be interpreted as a property of the root type or a member of one of its properties? At the very least a string array would need to be exported to address such scenarios...

    Per type workaround. Having said that, given that KeyPath conforms to the Equatable protocol, you can provide a custom, per type solution yourself. For instance:

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

    provide an extension for User-based key 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")
        }
    }
    

    usage:

    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 wouldn't really recommend this solution for production code, given the somewhat high maintenance, etc. But since you were curious this, at least, gives you a way forward ;)

    0 讨论(0)
  • 2021-02-01 15:08

    A bit late to the party, but I've stumbled upon a way of getting a key path string from NSObject subclasses at least:

    NSExpression(forKeyPath: \UIView.bounds).keyPath
    
    0 讨论(0)
  • 2021-02-01 15:14

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

    However, Swift key paths may not have String equivalents. It is a stated objective of Swift key paths that they do not require field names to be included in the executable. It's possible that a key path could be represented as a sequence of offsets of fields to get, or closures to call on an object.

    Of course, this directly conflicts with your own objective of avoiding to declare properties @objc. I believe that there is no built-in facility to do what you want to do.

    0 讨论(0)
提交回复
热议问题