web-dev-qa-db-ja.com

swiftのクラスのプロパティのリスト

注:Objective Cについて here について同様の質問が投稿されていますが、Swiftでそれを達成したいと思います。

Swiftのように宣言されたクラスがあります:

import UIKit

class EachDayCell : UITableViewCell
{

    @IBOutlet var dateDisplayLabel : UITextField
    @IBOutlet var nameDisplayLabel : UITextField

    @IBAction func goToPendingItems(sender : AnyObject) {
    }
    @IBAction func showDateSelectionPicker(sender : AnyObject) {
    }

    init(style: UITableViewCellStyle, reuseIdentifier: String!)
    {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
    }
}

ここでSwift enlisting:dateDisplayLabel、nameDisplayLabel。)の配列を取得したいです。

どうすればこれを達成できますか?

40
Devarshi

Mirrorを使用する

以下に、純粋なSwift解をいくつかの制限付きで示します。

_protocol PropertyNames {
    func propertyNames() -> [String]
}

extension PropertyNames
{
    func propertyNames() -> [String] {
        return Mirror(reflecting: self).children.flatMap { $0.label }
    }
}

class Person : PropertyNames {
    var name = "Sansa Stark"
    var awesome = true
}

Person().propertyNames() // ["name", "awesome"]
_

制限事項:

  • Objective-Cオブジェクトの空の配列を返します
  • 計算されたプロパティを返しません、すなわち:

    _var favoriteFood: String { return "Lemon Cake" }
    _
  • selfがクラスのインスタンス(たとえば、構造体)の場合、これはスーパークラスのプロパティを報告しません。

    _class Person : PropertyNames {
        var name = "Bruce Wayne"
    }
    
    class Superhero : Person {
        var hasSuperpowers = true
    }
    
    Superhero().propertyNames() // ["hasSuperpowers"] — no "name"
    _

    希望する動作に応じて、superclassMirror()を使用してこれを回避できます。

_class_copyPropertyList_を使用する

Objective-Cオブジェクトを使用している場合、このアプローチを使用できます。

_var count = UInt32()
let classToInspect = NSURL.self
let properties : UnsafeMutablePointer <objc_property_t> = class_copyPropertyList(classToInspect, &count)
var propertyNames = [String]()
let intCount = Int(count)
for var i = 0; i < intCount; i++ {
    let property : objc_property_t = properties[i]
    guard let propertyName = NSString(UTF8String: property_getName(property)) as? String else {
        debugPrint("Couldn't unwrap property name for \(property)")
        break
    }

    propertyNames.append(propertyName)
}

free(properties)
print(propertyNames)
_

classToInspectNSURLである場合のコンソールへの出力:

_["pathComponents", "lastPathComponent", "pathExtension", "URLByDeletingLastPathComponent", "URLByDeletingPathExtension", "URLByStandardizingPath", "URLByResolvingSymlinksInPath", "dataRepresentation", "absoluteString", "relativeString", "baseURL", "absoluteURL", "scheme", "resourceSpecifier", "Host", "port", "user", "password", "path", "fragment", "parameterString", "query", "relativePath", "hasDirectoryPath", "fileSystemRepresentation", "fileURL", "standardizedURL", "filePathURL"]_

これは遊び場では機能しません。 NSURLEachDayCellに置き換える(または同じロジックを拡張機能として再利用する)だけで機能します。

88
Aaron Brager

ここに別のバージョンがあります。これは非常にシンプルで純粋だと思います。

Swift 2.

protocol Reflectable {
  func properties()->[String]
}

extension Reflectable
{
    func properties()->[String]{
        var s = [String]()
        for c in Mirror(reflecting: self).children
        {
            if let name = c.label{
                s.append(name)
            }
        }
        return s
    }
}


class Test:Reflectable
{
    var name99:String = ""
    var name3:String = ""
    var name2:String = ""
}

Test().properties()

Swift 1.2

class Reflect:NSObject {
    func properties()->[String]
    {
        let m = reflect(self)
        var s = [String]()
        for i in 0..<m.count
        {
            let (name,_)  = m[i]
            if name == "super"{continue}
            s.append(name)
        }
        return s
    }
}

class Test:Reflect
{
    var name99:String = ""
    var name3:String = ""
    var name2:String = ""
}

Test().properties()
24
Kiny

ボリビア コードをSwift 4.に変換しました。この関数はNSObjectを取り込んで、オブジェクトのキーとタイプの辞書を返します。そのキーの

タイプはkindいことに注意してください。プリミティブプロパティの場合、エンジンは1文字の識別子(boolのB、intのiなど)を返しますが、Obj-C型の場合は_@"NSString"_のようなものを返します。これは本当に私にとっては単なるデバッグ機能であることに気がつきました。辞書をいじりたくない場合は、print行のコメントを外してコンソールにダンプします。 String(cString:cAttr)には、プロパティが変更可能かどうか、参照スタイルなど、多くの有用な情報も含まれています。 これについて詳しくは、Appleのドキュメントをご覧ください。

_func getKeysAndTypes(forObject:Any?) -> Dictionary<String,String> {
        var answer:Dictionary<String,String> = [:]
        var counts = UInt32();
        let properties = class_copyPropertyList(object_getClass(forObject), &counts);
        for i in 0..<counts {
            let property = properties?.advanced(by: Int(i)).pointee;

            let cName = property_getName(property!);
            let name = String(cString: cName)

            let cAttr = property_getAttributes(property!)!
            let attr = String(cString:cAttr).components(separatedBy: ",")[0].replacingOccurrences(of: "T", with: "");
            answer[name] = attr;
            //print("ID: \(property.unsafelyUnwrapped.debugDescription): Name \(name), Attr: \(attr)")
        }
        return answer;
    }
_
3
Sirens

Swift 3.1

let contorller = UIActivityViewController(activityItems: [url], applicationActivities: nil)
var count: UInt32 = 0
guard let properties = class_copyPropertyList(object_getClass(contorller), &count) else {
    return
}
for index in 0...count {
    let property1 = property_getName(properties[Int(index)])
    let result1 = String(cString: property1!)
    print(result1)
}
0
Ramis