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?
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.
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.
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.
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.
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:
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.
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.
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()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With