代码之家  ›  专栏  ›  技术社区  ›  Renzo Calla

在swift 4中作为字符串访问对象属性?[副本]

  •  0
  • Renzo Calla  · 技术社区  · 7 年前

    我在swift中有一个自定义类,我想使用订阅来访问它的属性,这可能吗?

    我想要的是这样的东西:

    class User {
        var name: String
        var title: String
    
        subscript(key: String) -> String {
            // Something here
            return // Return the property that matches the key…
        }
    
        init(name: String, title: String) {
            self.name = name
            self.title = title
        }
    }
    
    myUser = User(name: "Bob", title: "Superboss")
    myUser["name"] // "Bob"
    

    更新: 我找这个的原因是 GRMustache 从HTML模板呈现。我希望能够将我的模型对象传递给grmustache渲染器

    grmustache使用键控订阅objectforkeyedsubscript:method和键值编码valueforkey:method获取值。任何兼容对象都可以为模板提供值。

    https://github.com/groue/GRMustache/blob/master/Guides/view_model.md#viewmodel-objects

    0 回复  |  直到 12 年前
        1
  •  4
  •   Gwendal Roué    11 年前

    (此处为GrMustache作者)

    在一个面向swift的Mustache库出来之前,我建议让您的类继承自nsobject(以便它们具有 valueForKey: 方法)。然后,grmustache将使用此方法获取值。

    如果这仍然不起作用(呈现中为空值),可以尝试禁用grmustache安全功能(请参见 https://github.com/groue/GRMustache/blob/master/Guides/security.md#disabling-safe-key-access )

    如果您遇到任何其他问题,请在存储库中打开一个问题: https://github.com/groue/GRMustache/issues

    2015年2月2日编辑:grmustache.swift出局: http://github.com/groue/GRMustache.swift

        2
  •  13
  •   Benzi    9 年前

    这是一个使用反射的小技巧。可以使用以下行中的内容。

    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 {}
    

    然后创建 Person 访问它的关键属性。

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

    可以修改下标以始终返回属性值的插值字符串。

        3
  •  8
  •   shim    9 年前

    使用valueforkey应该可以使用属性的名称访问属性。确保使用的对象继承了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"
    
        4
  •  5
  •   Justin Oroz    8 年前

    在Benzi的答案中加入一些语法糖:

    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 {}
    

    然后创建 Person 访问它的关键属性。

    let p = Person(name: "John Doe", age: 18)
    
    p["name"] // gives "John Doe"
    p["age"] // gives 18
    
        5
  •  3
  •   Frank Wang    8 年前

    在swift 4中,shim上面的答案不再有效。有两件事你应该知道。

    首先,如果你想使用 value(forKey:) 函数,您的类必须继承 NSObject 是的。

    其次,由于objective-c对值类型一无所知,所以必须将 @objc 关键字在您的值类型属性和swift前面将为您做繁重的工作。

    下面是一个例子:

    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
    
        6
  •  2
  •   hpique    12 年前

    我想你可以:

    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
        }
    }
    

    不知道你的用例我会 强烈地 建议不要这样做。

    另一种方法:

    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
        }
    }
    

    值得注意的是,swift目前似乎并不支持按名称进行反射。这个 reflect 函数返回 Mirror 下标是 Int 基于,而不是 String 基于。