Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List of class's properties in swift

Note: there is a similar question posted for objective c over here, but I want to achieve it in swift.

I have a class declared in swift like this:

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

Now I want to get an array in swift enlisting: dateDisplayLabel, nameDisplayLabel.

How can I achieve this?

like image 812
Devarshi Avatar asked Jul 19 '14 20:07

Devarshi


People also ask

What are class properties in Swift?

In Swift, properties are associated values that are stored in a class instance. OR we can say properties are the associate values with structure, class, or enumeration. There are two kinds of properties: stored properties and computed properties. Stored properties are properties that are stored in the class's instance.

What is willSet and didSet in Swift?

willSet is called before the data is actually changed and it has a default constant newValue which shows the value that is going to be set. didSet is called right after the data is stored and it has a default constant oldValue which shows the previous value that is overwritten.

What is the lazy property in Swift?

A lazy stored property is a property whose initial value isn't calculated until the first time it's used. You indicate a lazy stored property by writing the lazy modifier before its declaration.

What does _: mean in Swift?

In Swift, the underscore operator (_) represents an unnamed parameter/label. In for loops, using the underscore looping parameter is practical if you do not need the looping parameter in the loop.


Video Answer


2 Answers

Using Mirror

Here's a pure Swift solution with some 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"] 

Limitations:

  • Returns an empty array for Objective-C objects
  • Will not return computed properties, i.e.:

    var favoriteFood: String { return "Lemon Cake" } 
  • If self is an instance of a class (vs., say, a struct), this doesn't report its superclass's properties, i.e.:

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

    You could work around this using superclassMirror() depending on your desired behavior.

Using class_copyPropertyList

If you're using Objective-C objects you can use this approach:

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) 

The output to the console if classToInspect is 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"]

This won't work in a playground. Just replace NSURL with EachDayCell (or reuse the same logic as an extension) and it should work.

like image 118
Aaron Brager Avatar answered Oct 04 '22 03:10

Aaron Brager


Here is another version.I think this is much simple and pure.

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() 
like image 35
Kiny Avatar answered Oct 04 '22 03:10

Kiny