web-dev-qa-db-fra.com

Récupérer la chaîne de Swift 4 nouvelle syntaxe de chemin de clé?

Comment obtenir une valeur de chaîne à partir de Swift 4 smart keypaths syntaxe (par exemple, \Foo.bar)? À ce stade, je suis curieux de savoir quoi que ce soit, peu importe si c'est compliqué.

J'aime l'idée d'associer des informations de type au chemin de clé intelligente. Mais toutes les API et les tiers ne sont pas encore là.

Il existe une ancienne méthode pour obtenir une chaîne pour le nom de la propriété avec une validation à la compilation par #keyPath(). Avec Swift 4 pour utiliser #keyPath(), vous devez déclarer une propriété comme @objc, Ce que je préfère éviter.

24
Dannie P

Pour les propriétés Objective-C sur les classes Objective-C, vous pouvez utiliser _kvcKeyPathString property pour l'obtenir.

Cependant, Swift peuvent ne pas avoir d'équivalents String. C'est un objectif déclaré de Swift qu'ils n'exigent pas que les noms de champ soient inclus dans le Il est possible qu'un chemin de clé puisse être représenté comme une séquence de décalages de champs à obtenir ou de fermetures pour appeler un objet.

Bien sûr, cela entre directement en conflit avec votre propre objectif d'éviter de déclarer des propriétés @objc. Je crois qu'il n'y a pas de fonction intégrée pour faire ce que vous voulez faire.

15
zneak

Réponse courte: vous ne pouvez pas. L'abstraction KeyPath est conçue pour encapsuler une propriété potentiellement imbriquée chemin de clé à partir d'un type racine donné. En tant que tel, l'exportation d'une seule valeur String peut ne pas avoir de sens dans le cas général.

Par exemple, la chaîne hypothétiquement exportée doit-elle être interprétée comme une propriété de type type racine ou comme membre de l'une de ses propriétés? À tout le moins, un tableau de chaînes devrait être exporté pour répondre à de tels scénarios ...

Solution de contournement par type . Cela dit, étant donné que KeyPath est conforme au protocole Equatable, vous pouvez fournir vous-même une solution personnalisée par type. Par exemple:

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

fournir une extension pour les chemins de clé basés sur User:

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 */

Je ne recommanderais pas vraiment cette solution pour le code de production, étant donné la maintenance un peu élevée, etc. Mais comme vous étiez curieux, cela vous donne au moins une voie à suivre;)

23
Paulo Mattos

Un peu tard pour la fête, mais je suis tombé sur un moyen d'obtenir au moins une chaîne de chemin de clé à partir des sous-classes NSObject:

NSExpression(forKeyPath: \UIView.bounds).keyPath
19
Andy Heard

Cela fonctionne comme une extension Swift 4:

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

Usage:

(\UIView.bounds).asString
// or
let keyPath = \UIView.bounds
keyPath.asString
0
Anton Plebanovich