通过Swift中的下标访问属性

时间:2023-01-23 21:28:03

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

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

What I want is something like this:

我想要的是这样的东西:

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"

Update: The reason why I'm looking for this is that I'm using GRMustache to render from HTML templates. I'd like to be able to just pass my model object to the GRMustache renderer…

更新:我寻找它的原因是我使用GRMustache从HTML模板中呈现。我希望能够将我的模型对象传递给GRMustache渲染器……

GRMustache fetches values with the keyed subscripting objectForKeyedSubscript: method and the Key-Value Coding valueForKey: method. Any compliant object can provide values to templates.

GRMustache使用键控子脚本对象forkeyedsubscript: method和键值编码valueForKey: method获取值。任何兼容的对象都可以向模板提供值。

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

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

6 个解决方案

#1


4  

(GRMustache author here)

(GRMustache作者)

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.

在快速导向的Mustache库出现之前,我建议让您的类从NSObject继承(以便它们具有valueForKey:方法)。然后,GRMustache将使用此方法获取值。

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)

如果这仍然不起作用(在呈现中是空白值),您可以尝试禁用GRMustache安全特性(参见https://github.com/groue/GRMustache/blob/master/Guides/security.md# disable - security -access)

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

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

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

2015年2月2日:GRMustache。斯威夫特是:http://github.com/groue/GRMustache.swift

#2


6  

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

使用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"

#3


6  

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.

然后创建一个Person并访问它的键控属性。

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.

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

#4


2  

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.

值得注意的是,Swift目前似乎不支持使用姓名进行反射。反射函数返回一个镜像,其下标为Int型,而不是字符串型。

#5


2  

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

在Swift 4中,Shim上面的答案不再适用。有两件事你应该注意。

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

首先,如果您想使用value(forKey:)函数,您的类必须继承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.

其次,由于Objective-C不知道任何关于值类型的信息,所以必须将@objc关键字放在值类型属性前面,Swift将为您完成繁重的工作。

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

#6


0  

Adding some syntax sugar to Benzi's answer:

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

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

然后创建一个Person并访问它的键控属性。

let p = Person(name: "John Doe", age: 18)

p["name"] // gives "John Doe"
p["age"] // gives 18

#1


4  

(GRMustache author here)

(GRMustache作者)

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.

在快速导向的Mustache库出现之前,我建议让您的类从NSObject继承(以便它们具有valueForKey:方法)。然后,GRMustache将使用此方法获取值。

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)

如果这仍然不起作用(在呈现中是空白值),您可以尝试禁用GRMustache安全特性(参见https://github.com/groue/GRMustache/blob/master/Guides/security.md# disable - security -access)

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

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

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

2015年2月2日:GRMustache。斯威夫特是:http://github.com/groue/GRMustache.swift

#2


6  

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

使用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"

#3


6  

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.

然后创建一个Person并访问它的键控属性。

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.

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

#4


2  

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.

值得注意的是,Swift目前似乎不支持使用姓名进行反射。反射函数返回一个镜像,其下标为Int型,而不是字符串型。

#5


2  

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

在Swift 4中,Shim上面的答案不再适用。有两件事你应该注意。

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

首先,如果您想使用value(forKey:)函数,您的类必须继承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.

其次,由于Objective-C不知道任何关于值类型的信息,所以必须将@objc关键字放在值类型属性前面,Swift将为您完成繁重的工作。

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

#6


0  

Adding some syntax sugar to Benzi's answer:

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

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

然后创建一个Person并访问它的键控属性。

let p = Person(name: "John Doe", age: 18)

p["name"] // gives "John Doe"
p["age"] // gives 18