19

我在 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 渲染器……</p>

GRMustache 使用键控下标 objectForKeyedSubscript: 方法和 Key-Value Coding valueForKey: 方法获取值。任何兼容的对象都可以为模板提供值。

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

4

6 回答 6

16

这有点像使用反射的技巧。可以使用类似于以下内容的东西。

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

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

于 2017-01-17T17:13:59.343 回答
10

使用 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"
于 2015-01-30T21:51:08.530 回答
10

在 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
于 2018-06-28T19:37:48.317 回答
5

(这里是GRMustache作者)

在一个面向 swift 的 Mustache 库出来之前,我建议让你的类继承自 NSObject(这样它们就有valueForKey:方法)。然后,GRMustache 将使用此方法获取值。

如果这仍然不起作用(渲染中的空白值),您可以尝试禁用 GRMustache 安全功能(请参阅https://github.com/groue/GRMustache/blob/master/Guides/security.md#disabling-safe -钥匙访问

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

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

于 2014-06-12T05:54:54.473 回答
4

Shim 的上述回答在 Swift 4 中不再适用。您应该注意两件事。

首先,如果你想使用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
于 2017-10-19T13:14:40.177 回答
2

我想你可以这样做:

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函数返回 a Mirror,其下标是Int基于的,而不是String基于的。

于 2014-06-10T10:41:23.367 回答