Swift 2.0 Get Mirrored Superclass Properties
One possible solution would be to implement toDictionary()
as a method of Mirror
itself, so that you can traverse recursively
to the superclass mirror:
extension Mirror {
func toDictionary() -> [String: AnyObject] {
var dict = [String: AnyObject]()
// Properties of this instance:
for attr in self.children {
if let propertyName = attr.label {
dict[propertyName] = attr.value as? AnyObject
}
}
// Add properties of superclass:
if let parent = self.superclassMirror() {
for (propertyName, value) in parent.toDictionary() {
dict[propertyName] = value
}
}
return dict
}
}
and then use that to implement the protocol extension method:
extension ListsProperties {
func toDictionary() -> [String: AnyObject] {
return Mirror(reflecting: self).toDictionary()
}
}
Mirroring Not Picking Up Base Class on Swift 3
You need to use the superclassMirror: Mirror?
property for that. For instance:
for attr in widgetMirror.superclassMirror!.children {
print(attr.label!)
}
prints the expected results:
name
uuid
Update. If you keep running into this, add this Mirror
extension to your toolkit:
extension Mirror {
var allChildren: [Mirror.Child] {
var allChildren: [Mirror.Child] = []
var mirror: Mirror! = self
repeat {
allChildren.append(contentsOf: mirror.children)
mirror = mirror.superclassMirror
} while mirror != nil
return allChildren
}
}
Usage:
for attr in widgetMirror.allChildren {
print(attr.label!)
}
How can I find the type of a property dynamically in swift (Reflection/Mirror)?
You don't need to inherit from NSObject
(unless you have a good reason to).
class Employee {
var id: String?
var someArray: [Employee]?
}
let employee = Employee()
for property in Mirror(reflecting: employee).children {
print("name: \(property.label) type: \(type(of: property.value))")
}
Output
name: Optional("id") type: Optional<String>
name: Optional("someArray") type: Optional<Array<Employee>>
This also works with Structs
Using getter/setter for property makes it not appear in reflection (mirror)
For the first problem I ended up using the following extension, which does see properties with getters/setters unlike Mirror:
extension NSObject {
func propertiesNames() -> [String] {
var count : UInt32 = 0
let classToInspect = type(of: self)
guard let properties : UnsafeMutablePointer <objc_property_t> = class_copyPropertyList(classToInspect, &count) else { return [] }
var propertyNames : [String] = []
let intCount = Int(count)
for i in 0..<intCount {
let property : objc_property_t = properties[i]
let propertyName = NSString(utf8String: property_getName(property))!
propertyNames.append(propertyName as String)
}
free(properties)
return propertyNames
}
}
As for the second issue I ended up copying each property over from the theme to the button as they are always the same. The goal was to avoid having to maintain a Theme class to bridge values every time something new is implemented in ZFButton.
Swift: How to check for base class and superclass on a subclass
You have to expose the contained type as a typealias. Here is the solution.
protocol BaseClass { }
class Person : BaseClass { }
class Parent : Person { }
class GenericClass<T: BaseClass> {
typealias Contained = T
}
let myGeneric = GenericClass<Parent>()
print("myGeneric is GenericClass<BaseClass>: \(type(of: myGeneric).Contained() is BaseClass)")
How iterate through all properties of different classes in Swift?
This is what reflection is for. You can add a property / method to the Car
class that list all the properties of the current class, plus those of the superclass. When this property / method is dynamically applied to the subclasses, it will give what you are looking for.
We need an extension to Mirror
that returns all properties of the current instance and those of its superclass recursively, taken from Martin R's answer:
extension Mirror {
func toDictionary() -> [String: Any] {
var dict = [String: Any]()
// Attributes of this class
for attr in self.children {
if let propertyName = attr.label {
dict[propertyName] = attr.value
}
}
// Attributes of superclass
if let superclass = self.superclassMirror {
for (propertyName, value) in superclass.toDictionary() {
dict[propertyName] = value
}
}
return dict
}
}
class Car: CustomDebugStringConvertible {
// ...
var debugDescription: String {
let dict = Mirror(reflecting: self).toDictionary()
return dict.map { "\($0.key) = \($0.value)" }.joined(separator: "\n")
}
}
Usage:
var allClassesArrays = [carrsArray, sportCarsArray, tankerCarsArray]
for car in allClassesArrays.flatMap({ $0 }) {
print(car.debugDescription, terminator: "\n\n")
}
You of course don't have to conform Car
to CustomDebugStringConvertible
or name the property debugDescription
. I just find them convenient since the debugger will use the debugDescription
when you type po car
.
Swift Mirror reflection not returning properties on UIVIew
Not sure what you are trying to achieve but UIView inherits NSObject. Because of this, you have much of the objc runtime at your disposal. So as an alternative, you could do the following:
import UIKit
extension NSObject {
func propertysNames() -> [String]{
var count : UInt32 = 0
let classToInspect = self.dynamicType
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]
let propertyName = NSString(UTF8String: property_getName(property))!
propertyNames.append(propertyName as String)
}
free(properties)
return propertyNames
}
}
print(UIView().propertysNames())
// prints: "["_mayRemainFocused", "_sensitivitySize", "skipsSubviewEnumeration", "viewTraversalMark", "viewDelegate", "monitorsSubtree", "backgroundColorSystemColorName", "currentScreenScale", "maskView", "_userInterfaceIdiom", "hash", "superclass", "description", "debugDescription", "gesturesEnabled", "deliversTouchesForGesturesToSuperview", "deliversButtonsForGesturesToSuperview", "_shouldReverseLayoutDirection", "leadingAnchor", "trailingAnchor", "leftAnchor", "rightAnchor", "topAnchor", "bottomAnchor", "widthAnchor", "heightAnchor", "centerXAnchor", "centerYAnchor", "firstBaselineAnchor", "lastBaselineAnchor", "_keyboardOrientation", "_touchForceObservable", "_inheritedRenderConfig", "_lightStyleRenderConfig", "_accessoryViewFrame", "unsatisfiableConstraintsLoggingSuspended", "hash", "superclass", "description", "debugDescription", "hash", "superclass", "description", "debugDescription", "userInteractionEnabled", "tag", "layer", "focused", "semanticContentAttribute", "interactionTintColor", "_layoutDebuggingIdentifier", "_countOfMotionEffectsInSubtree", "_maskView", "_ancestorDefinesTintColor", "_ancestorDefinesTintAdjustmentMode", "_presentationControllerToNotifyOnLayoutSubviews", "_rawLayoutMargins", "_inferredLayoutMargins", "_dontUpdateInferredLayoutMargins", "_tracksFocusedAncestors", "_countOfFocusedAncestorTrackingViewsInSubtree", "_mutableLayoutGuides", "_mutableLayoutArrangements", "_hiddenManagedByLayoutArrangementCount", "_pendingHiddenCount", "previewingSegueTemplateStorage", "_continuousCornerRadius", "_canBeParentTraitEnviroment", "_layoutEngine", "_boundsWidthVariable", "_boundsHeightVariable", "_minXVariable", "_minYVariable", "_internalConstraints", "_constraintsExceptingSubviewAutoresizingConstraints", "unsatisfiableConstraintsLoggingSuspended", "_shouldArchiveUIAppearanceTags", "_interactionTintColor", "_backdropMaskViewForGrayscaleTint", "_backdropMaskViewForColorTint", "_backdropMaskViewForFilters", "_backdropMaskViews", "_wantsGeometryChangeNotification", "contentSizeNotificationToken", "layoutMarginsGuide", "readableContentGuide", "hash", "superclass", "description", "debugDescription", "traitCollection", "preferredFocusedView", "center", "bounds", "transform", "collisionBoundsType", "collisionBoundingPath"]\n"
Also, I do see some weirdness applying your code to UIKit objects. Not sure what the variable is that causes it to fail. It seems to work fine on NSObject types written in Swift:
import UIKit
class Fruit {
var type=1
var name="Apple"
var delicious=true
}
var s = [String]()
for c in Mirror(reflecting: Fruit()).children
{
if let name = c.label{
s.append(name)
}
}
print(s)
// works: "["type", "name", "delicious"]\n"
class FruitNSObject: NSObject {
var type:NSNumber=1
var name:NSString="Apple"
var delicious=true
}
s = [String]()
for c in Mirror(reflecting: FruitNSObject()).children
{
if let name = c.label {
s.append(name)
}
}
print(s)
// works: "["type", "name", "delicious"]\n"
s = [String]()
for c in Mirror(reflecting: UIView()).children
{
if let name = c.label {
s.append(name)
}
}
print(s)
// doesn't work: "[]\n"
s = [String]()
for c in Mirror(reflecting: UIViewController()).children
{
if let name = c.label {
s.append(name)
}
}
print(s)
// doesn't work: "[]\n"
So either this is a bug or there is some limitation in the Swift <-> ObjC in the current version of Swift. Perhaps it has to do with what @user3441734 pointed out in his answer.
BTW, all code was run on the most current version of Xcode (that's 7.1.1) in a playground.
Will an array of a superclass contain subclasses as well?
Tree options here
A: Change the array type to Student
var students: [Student]()
B: Cast each element from the persons array to a Student. Ideally inside a for each person.
guard let student = person as? Student else {
return // or continue if inside a for loop
}
Then u will have access to that student variable.
C: Or if they might be students and persons at the same time in the array then
for person in persons {
switch person{
case let student as Student: //student case
//do something
default: //person case
//do something
}
}
Related Topics
Swift - Reorder Uitableview Cells
Swift, Sprite Kit Game: Have Circle Disappear in Clockwise Manner? on Timer
Uipickerview Selectrow Doesn't Works
How to Implement Protocol Methods That Return Covariant Selfs
Swift Utf8 Encoding and Non Utf8 Character
How to Declare Swift Implicitly Unwrapped Optional as a Constant
Store Encodables in a Swift Dictionary
How to Share Data Between Tab View Controllers
What Is the Swift Equivalent of -[Nsobject Description]
iOS 13: Threading Violation: Expected the Main Thread
System Volume Change Observer Not Working on iOS 15
Safe to Signal Semaphore Before Deinitialization Just in Case
Using Uiapplicationdelegateadaptor to Get Callbacks from Userdidacceptcloudkitsharewith Not Working
Get Signed Integer from Swift String of Binary
How to Set an Environment Object in Preview
How Do Generators Whose Element Is Optional Know When They'Ve Reached the End
Swift - Get File Path of Currently Opened Document in Another Application