Mirror not working in Swift when iterating through children of an Objective-C object
Mirror does not seem to work with Objective-C classes. But, you can use the class_copyPropertyList function to retrieve all the properties from an Objective-C class.
var outCount : UInt32 = 0
let properties = class_copyPropertyList(ObjectCTest.self, &outCount)
print(outCount)
for i : UInt32 in 0..<outCount
{
let strKey : NSString? = NSString(CString: property_getName(properties[Int(i)]), encoding: NSUTF8StringEncoding)
let attrs : NSString? = NSString(CString: property_getAttributes(properties[Int(i)]), encoding: NSUTF8StringEncoding)
print(strKey)
print(attrs)
}
get Child of Mirror.Children by index
The type Children
is actually a typedef for AnyForwardCollection<Child>
.
You can't index into an AnyForwardCollection
with any old Int
. You need to use an AnyForwardIndex
. You can use startIndex
to get the starting index and advancedBy()
to move forward.
let obj = demo()
let reflected = Mirror( reflecting: obj)
let idx = reflected.children.startIndex
let first = reflected.children[idx]
let thirdIdx = idx.advancedBy(2)
let third = reflected.children[thirdIdx]
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!)
}
Swift 3 Reflection - Iterating over properties
According to documentation about Child
here :
Child
An element of the reflected instance’s structure. The optional label may be used when appropriate, e.g. to represent the name of a
stored property or of an active enum case, and will be used for lookup
when Strings are passed to the descendant method.
Since type child in mirror is defined as
typealias Child = (label: String?, value: Any)
Therefore all names are printed as Optionals.
To get the label names you can use optional binding
I have made some changes and tried this in playground:
class FooModel
{
func toString() -> String
{
var result = "[\(String(describing: type(of: self))) "
let mirror = Mirror(reflecting: self)
mirror.children.forEach
{
child in
print(child)
if let label = child.label {
result += "\(label): \(child.value), "
}
}
return "\(result)]"
}
}
class FooProject : FooModel
{
var id = 0
var name = ""
var announcement:String!
var showAnnouncement = false
var isCompleted = false
var completedOn:String!
var suiteMode = 0
var url = ""
init(id: Int, name: String, completedOn: String) {
self.completedOn = completedOn
self.id = id
self.name = name
//...
}
}
let fooProj = FooProject(id: 10, name: "Name", completedOn: "Sunday")
print(fooProj.toString())
Ouptut is :
[FooProject id: 10, name: Name, announcement: nil, showAnnouncement: false, isCompleted: false, completedOn: Sunday, suiteMode: 0, url: , ]
HTH..
How to extract optional typed values from Mirror children in Swift?
It seems this isn't possible in Swift 2.x.
Since the properties are optionals, you would have to cast to NSDate?
and String?
, respectively, like this:
if let val = value as? NSDate? {
// val is Optional<NSDate>
}
Unfortunately, the compiler doesn't allow this (I’m not sure why): // error: cannot downcast from 'protocol<>' to a more optional type 'NSDate?'
.
This answer from bubuxu provides a clever workaround that would work if you had a Mirror
for each property. The mirror's displayStyle
property tells you if it is an optional, and you can then extract the wrapped value manually. So this would work:
let child = Mirror(reflecting: myBook.date)
child.displayStyle
if child.displayStyle == .Optional {
if child.children.count == 0 {
// .None
} else {
// .Some
let (_, some) = child.children.first!
if let val = some as? NSDate {
print(val)
}
}
}
But this depends on having a Mirror
for each property, and it seems you can’t traverse a Mirror
's children to retrieve Mirror
s for them.
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()
}
}
How to get class properties label in swift 3?
You can use Mirror in swift3 to get all the properties of a class like this
class BasicD{
public var id_: Int64 = 0
public var a: Int32 = 0
public var c: NSData?
public var d: NSData?
}
let obj = BasicD()
var arrayOfObjects: [String] = []
let mirror = Mirror(reflecting: obj)
for child in mirror.children {
guard let key = child.label else { continue }
arrayOfObjects.append(key)
print(key)
}
print(arrayOfObjects)
Here arrayOfObjects
contains all your variable name of class BasicD
Related Topics
How to Add Followed Text to Uitextfield
iOS Swift App with More Photos: Performance and Storage Suggestions
iOS Development App Startup Crash
Game Exits from Pause State After Resuming It from Background in Swift
Swift:Background Color Fading Animation (Spritekit)
Error After Importing Swift into Objective-C
iOS Uiimagepickercontroller: Any Way of Getting the Date of the Chosen Picture
How to Use Alamofires Servertrustpolicy.Disableevaluation in Swift 3
Delegate Method to Uitableviewcell Swift
Aes 128 Message Decryption -- Swift, iOS
Uitextfield Starting Cursor Position Is Wrong
Uitraitcollection Clarification
Impelementation of Rtcdatachannel of Webrtc in iOS
Clipping Sound with Opus on Android, Sent from iOS
Opening Viewcontroller in Appdelegate While Keeping Tabbar
Why Does It Take Such a Long Time for UI to Be Updated from Background Thread