web-dev-qa-db-fra.com

Liste des biens immobiliers de la classe dans swift

Remarque: une question similaire a été posée pour l’objectif C sur ici , mais je souhaite y parvenir 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 atteindre cet objectif?

37
Devarshi

Utiliser Mirror

Voici une solution Swift pure avec quelques limitations:

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

Limites:

  • 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 une struct, par exemple), cela ne rapporte pas les propriétés de sa superclasse,

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

    Vous pouvez contourner ce problème en utilisant superclassMirror() en fonction de votre comportement souhaité.

Utiliser class_copyPropertyList

Si vous utilisez des objets Objective-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 sur 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"]

Cela ne fonctionnera pas dans un terrain de jeu. Il suffit de remplacer NSURL par EachDayCell (ou de réutiliser la même logique comme une extension) et cela devrait fonctionner.

84
Aaron Brager

Voici une autre version.Je pense que c'est beaucoup 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
Kiny

J'ai converti le code bolivia en Swift 4. Cette fonction prend un objet NSObject et renvoie un dictionnaire des clés de l'objet et du type de cette clé.

Notez que les types sont un peu moche. Pour les propriétés primitives, le moteur renvoie un identificateur d'une lettre (par exemple, B pour bool, i pour int, etc.), mais pour les types Obj-C, il renvoie des éléments tels que @"NSString". Voir que c'est vraiment juste une fonction de débogage pour moi ne me dérangeait pas. Si vous ne voulez pas manipuler le dictionnaire, vous pouvez simplement supprimer le commentaire de la ligne print et le vider dans la console. String(cString:cAttr) contient également de nombreuses informations utiles, notamment si la propriété est modifiable, son style de référence, etc. Pour plus d'informations à ce sujet, 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;
    }
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