Reputation: 20257
I have a very strange issue related to using Mirror in Swift. I am iterating over all of the properties in a class called Test:
let test = Test()
let mirror = Mirror(reflecting: test)
for i in mirror.children {
...
}
If I implement my Test class in Swift, I have three values in children that is iterated over:
class Test: NSObject {
var device: NSNumber!
var version: NSNumber!
var application: NSString!
}
However, if I implement the Test class in Objective C, I get zero children:
@interface ObjectCTest : NSObject
@property (nonatomic, strong) NSNumber *device;
@property (nonatomic, strong) NSNumber *version;
@property (nonatomic, strong) NSString *application;
@end
Does anyone know what might be going on? I'm starting to think it might be something to do with Xcode project settings, as I have other projects that this works for. Any suggestions are appreciated!
Upvotes: 7
Views: 2277
Reputation: 310
protocol Reflectable: AnyObject {
func reflected() -> [String: Any?]
}
extension Reflectable {
func reflected() -> [String: Any?] {
let mirror = Mirror(reflecting: self)
var dict: [String: Any?] = [:]
for child in mirror.children {
guard let key = child.label else {
continue
}
dict[key] = child.value
}
return dict
}
var reflectedString: String {
let reflection = reflected()
var result = String(describing: self)
result += " { \n"
for (key, val) in reflection {
result += "\t\(key): \(val ?? "null")\n"
}
return result + "}"
}
}
extension Reflectable where Self: NSObject {
func reflected() -> [String : Any?] {
var count: UInt32 = 0
guard let properties = class_copyPropertyList(Self.self, &count) else {
return [:]
}
var dict: [String: Any] = [:]
for i in 0..<Int(count) {
let name = property_getName(properties[i])
guard let nsKey = NSString(utf8String: name) else {
continue
}
let key = nsKey as String
guard responds(to: Selector(key)) else {
continue
}
dict[key] = value(forKey: key)
}
free(properties)
return dict
}
}
Upvotes: 2
Reputation: 3601
It's seems like the other answer is right about NSObject classes not being able to use mirror.
However, there is a better way to get properties: - valueForKeyPath:
or value(forKeyPath:)
Upvotes: 1
Reputation: 5797
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)
}
Upvotes: 11