Access properties via subscripting in Swift

后端 未结 6 1587
情歌与酒
情歌与酒 2021-01-04 00:43

I have a custom class in Swift and I\'d like to use subscripting to access its properties, is this possible?

What I want is something like this:

clas         


        
相关标签:
6条回答
  • 2021-01-04 00:58

    Shim's answer above doesn't work anymore in Swift 4. There are two things you should be aware of.

    First of all, if you want to use value(forKey:) function, your class must inherit NSObject.

    Secondly, since Objective-C doesn't know anything about value type, you have to put the @objc keyword in front of your value type properties and Swift will do the heavy-lifting for you.

    Here is the example:

    import Foundation
    
    class Person: NSObject {
        @objc var name: String = "John Dow"
        @objc var age: Int = 25
        @objc var height: Int = 180
    
        subscript(key: String) -> Any? {
            return self.value(forKey: key)
        }
    }
    
    let person: Person = Person()
    
    person["name"] // "John Dow"
    person["age"] // 25
    person["height"] // 180
    
    0 讨论(0)
  • 2021-01-04 01:01

    I suppose you could do:

    class User {
        let properties = Dictionary<String,String>()
    
        subscript(key: String) -> String? {
            return properties[key]
        }
    
        init(name: String, title: String) {
            properties["name"] = name
            properties["title"] = title
        }
    }
    

    Without knowing your use case I would strongly advise against doing this.

    Another approach:

    class User {
        var name : String
        var title : String
    
        subscript(key: String) -> String? {
            switch key {
                case "name" : return name
                case "title" : return title
                default : return nil
            }
        }
    
        init(name: String, title: String) {
            self.name = name
            self.title = title
        }
    }
    

    It might be worth noting that Swift doesn't appear to currently support reflection by names. The reflect function returns a Mirror whose subscript is Int based, not String based.

    0 讨论(0)
  • 2021-01-04 01:04

    Adding some syntax sugar to Benzi's answer:

    protocol PropertyReflectable { }
    
    extension PropertyReflectable {
        subscript(key: String) -> Any? {
            let m = Mirror(reflecting: self)
            return m.children.first { $0.label == key }?.value
        }
    }
    
    struct Person {
        let name: String
        let age: Int
    }
    
    extension Person : PropertyReflectable {}
    

    Then create a Person and access it's keyed properties.

    let p = Person(name: "John Doe", age: 18)
    
    p["name"] // gives "John Doe"
    p["age"] // gives 18
    
    0 讨论(0)
  • 2021-01-04 01:07

    This is a bit of a hack using reflection. Something along the lines of the following could be used.

    protocol PropertyReflectable { }
    
    extension PropertyReflectable {
        subscript(key: String) -> Any? {
            let m = Mirror(reflecting: self)
            for child in m.children {
                if child.label == key { return child.value }
            }
            return nil
        }
    }
    
    struct Person {
        let name: String
        let age: Int
    }
    
    extension Person : PropertyReflectable {}
    

    Then create a Person and access it's keyed properties.

    let p = Person(name: "John Doe", age: 18)
    
    p["name"] // gives "John Doe"
    p["age"] // gives 18
    

    You could modify the subscript to always return an interpolated string of the property value.

    0 讨论(0)
  • 2021-01-04 01:09

    Using valueForKey should enable you to access properties using their names. Be sure that you're working with a object that inherit NSObject

    class people: NSObject {
        var age: NSString = "44"
        var height: NSString = "153"
    }
    
    let person:people = people()
    
    let stringVariable = "age"
    
    person.valueForKey("age")
    // Print "44"
    
    person.valueForKey("\(stringVariable)")
    // Print "44"
    
    0 讨论(0)
  • 2021-01-04 01:17

    (GRMustache author here)

    Until a swift-oriented Mustache library is out, I suggest having your classes inherit from NSObject (so that they have the valueForKey: method). GRMustache will then fetch values with this method.

    In case this would still not work (blank values in the rendering), you may try to disable GRMustache security features (see https://github.com/groue/GRMustache/blob/master/Guides/security.md#disabling-safe-key-access)

    Should you experience any other trouble, please open an issue right into the repository: https://github.com/groue/GRMustache/issues

    EDIT February 2, 2015: GRMustache.swift is out: http://github.com/groue/GRMustache.swift

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