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"
更新:これを探している理由は、HTMLテンプレートからレンダリングするために GRMustache を使用しているためです。モデルオブジェクトをGRMustacheレンダラーに渡すだけでいいのですが…
GRMustacheは、キー付き添え字objectForKeyedSubscript:メソッドとKey-ValueコーディングvalueForKey:メソッドを使用して値をフェッチします。準拠するオブジェクトはすべて、テンプレートに値を提供できます。
https://github.com/groue/GRMustache/blob/master/Guides/view_model.md#viewmodel-objects
(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
これは、リフレクションを使用したちょっとしたハックです。次のようなものを使用できます。
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
添え字を変更して、プロパティ値の補間された文字列を常に返すようにすることができます。
ベンジの答えにいくつかのシンタックスシュガーを追加する:
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
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"
上記のShimの答えは、Swift 4では機能しなくなりました。注意すべき点が2つあります。
まず、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
私はあなたができると思います:
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
を返します。