web-dev-qa-db-ja.com

Swift)の添え字でプロパティにアクセスします

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

17
Matias Korhonen

(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

5
Gwendal Roué

これは、リフレクションを使用したちょっとしたハックです。次のようなものを使用できます。

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

添え字を変更して、プロパティ値の補間された文字列を常に返すようにすることができます。

13
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
9
Justin Oroz

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"
8
mizerablebr

上記の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
3
Frank Wang

私はあなたができると思います:

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を返します。

2
hpique