web-dev-qa-db-ja.com

Swift変数の実際の名前を文字列として取得

だから私はSwiftで実際の変数名を文字列として取得しようとしていますが、それを行う方法を見つけていません...またはこの問題と解決策を間違った角度で見ています。

だからこれは基本的に私がやりたいことです:

var appId: String? = nil

//This is true, since appId is actually the name of the var appId
if( appId.getVarName = "appId"){
    appId = "CommandoFurball"
}

残念ながら、Apple docsでこれに近いものを見つけることができませんでしたが、これは次のとおりです。

varobj.self or reflect(var).summary 

ただし、これにより、変数自体の内部の情報またはこの場合の変数のタイプがStringであるという情報が得られ、変数の実際の名前が必要になります。

40
S.H.

この回答 から更新されたとおり、Swift 3 via #keyPath

NSPredicate(format: "%K == %@", #keyPath(Person.firstName), "Andrew")
27
ColinE

これは、Swift 3#keyPath()を使用して公式にサポートされています

https://github.com/Apple/Swift-evolution/blob/master/proposals/0062-objc-keypaths.md

使用例は次のようになります。

NSPredicate(format: "%K == %@", #keyPath(Person.firstName), "Wendy")

Swift 4では、さらに良いものがあります:\KeyPath表記

https://github.com/Apple/Swift-evolution/blob/master/proposals/0161-key-paths.md

NSPredicate(format: "%K == %@", \Person.mother.firstName, "Wendy")

// or

let keyPath = \Person.mother.firstName
NSPredicate(format: "%K == %@", keyPath, "Andrew")

速記は歓迎すべき追加であり、変数からキーパスを参照できることは非常に強力です

48
Andrew

これは私の解決策です

class Test { 
    var name: String = "Ido"
    var lastName: String = "Cohen"
}

let t = Test()
let mirror = Mirror(reflecting: t)

for child in mirror.children {
    print(child.label ?? "")
}

印刷されます

name
lastName
5
Ido Cohen

最良の解決策は ここ です

指定されたリンクから

import Foundation

extension NSObject {
//
// Retrieves an array of property names found on the current object
// using Objective-C runtime functions for introspection:
// https://developer.Apple.com/library/mac/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html
//
func propertyNames() -> Array<String> {
    var results: Array<String> = [];

    // retrieve the properties via the class_copyPropertyList function
    var count: UInt32 = 0;
    var myClass: AnyClass = self.classForCoder;
    var properties = class_copyPropertyList(myClass, &count);

    // iterate each objc_property_t struct
    for var i: UInt32 = 0; i < count; i++ {
        var property = properties[Int(i)];

        // retrieve the property name by calling property_getName function
        var cname = property_getName(property);

        // covert the c string into a Swift string
        var name = String.fromCString(cname);
        results.append(name!);
    }

    // release objc_property_t structs
    free(properties);

    return results;
}

}

1

Swift解決策を思いつきましたが、残念ながらはInts、Floats、およびDoubles 私は信じている。

func propertyNameFor(inout item : AnyObject) -> String{
    let listMemAdd = unsafeAddressOf(item)
    let propertyName =  Mirror(reflecting: self).children.filter { (child: (label: String?, value: Any)) -> Bool in
        if let value = child.value as? AnyObject {
            return listMemAdd == unsafeAddressOf(value)
        }
        return false
        }.flatMap {
            return $0.label!
    }.first ?? ""

    return propertyName
}

var mutableObject : AnyObject = object
let propertyName = MyClass().propertyNameFor(&mutableObject)

オブジェクトのプロパティのメモリアドレスを比較し、一致するものがあるかどうかを確認します。 Ints、Floats、Doublesがanyobject型ではないため機能しない理由。ただし、これらをNSNumbersに変換すると、anyobjectとして渡すことができます。したがって、メモリアドレスが変更されます。 彼らはここでそれについて話します

私のアプリでは、カスタムクラスにのみ必要なため、まったく邪魔になりませんでした。だから誰かがこれを役に立つと思うかもしれません。誰かが他のデータ型でこれを機能させることができれば、それはかなりクールです。

1
David Rees

これは動作します:

struct s {
    var x:Int = 1
    var y:Int = 2
    var z:Int = 3
}

var xyz = s()

let m = Mirror(reflecting: xyz)

print(m.description)
print(m.children.count)
for p in m.children {
    print(p.label as Any)
}
1
cdeerinck