Liste des propriétés de class dans swift

Note: il y a une question similaire affichée pour l'objectif c sur ici , mais je veux l'atteindre dans swift.

j'ai une classe déclarée dans swift comme ceci:

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)
    }
}

maintenant je veux obtenir un tableau dans swift enlisting: dateDisplayLabel, nameDisplayLabel.

Comment puis-je y parvenir?

35
demandé sur Community 2014-07-20 00:28:06

4 réponses

utilisant Mirror

Voici une solution pure et rapide avec quelques limites:

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

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

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

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

Limitations:

  • retourne un tableau vide pour les objets Objective-C
  • ne renverra pas les propriétés calculées, c'est à dire:

    var favoriteFood: String { return "Lemon Cake" }
    
  • si self est une instance d'une classe (vs., disons, une structure), cela ne rapport de sa super-classe de propriétés, c'est à dire:

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

    , Vous pouvez contourner cela en utilisant superclassMirror() en fonction de votre comportement souhaité.

utilisant class_copyPropertyList

si vous utilisez des objets Objectif-C, vous pouvez utiliser cette approche:

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)

la sortie vers la console si classToInspect est NSURL :

["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"]

ça ne marchera pas dans un terrain de jeu. Il suffit de remplacer NSURL par EachDayCell (ou réutiliser la même logique qu'une extension) et cela devrait fonctionner.

78
répondu Aaron Brager 2016-08-01 13:49:49

Voici une autre version.Je pense que c'est très simple et pur.

Swift 2.0

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
répondu Kiny 2017-01-14 20:59:49

j'ai converti code de la Bolivie en Swift 4. Cette fonction prend dans un NSObject et renvoie un dictionnaire des clés de l'objet et le type de cette clé .

notez que les types sont un peu moches. Pour les propriétés primitives, le moteur renvoie un identificateur d'une lettre (comme B pour bool, i pour int, etc.) mais pour les types Obj-C il renvoie des choses comme @"NSString" . Vu que c'est vraiment juste une fonction de débogage pour moi ça ne me dérangeait pas. Si vous ne voulez pas jouer avec le dictionnaire, vous pouvez simplement décommenter la ligne print et le faire jeter à la console. String(cString:cAttr) contient également beaucoup d'informations utiles, y compris si la propriété est mutable, son style de référence, et bien plus encore. pour plus d'informations sur ce Voici la documentation D'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;
    }
2
répondu Sirens 2018-01-21 21:59:42

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
répondu Ramis 2017-04-14 07:13:31