我在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:方法和键值编码valueForKey:方法获取值。任何兼容对象都可以为模板提供值。
https://github.com/groue/GRMustache/blob/master/Guides/view_model.md#viewmodel-objects
答案 0 :(得分:11)
这是一个使用反射的黑客攻击。可以使用下面的内容。
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
您可以修改下标以始终返回属性值的插值字符串。
答案 1 :(得分:8)
使用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"
答案 2 :(得分:5)
在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
答案 3 :(得分:4)
(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
答案 4 :(得分:3)
上面的Shim的回答在Swift 4中不再起作用。你应该注意两件事。
首先,如果您想使用value(forKey:)
函数,您的类必须继承NSObject
。
其次,由于Objective-C对值类型一无所知,你必须将@objc
关键字放在值类型属性的前面,Swift将为你做重任。< / p>
以下是示例:
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
答案 5 :(得分: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
函数返回Mirror
,其下标为Int
,而不是基于String
。