FLEXMirror.m 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. //
  2. // FLEXMirror.m
  3. // FLEX
  4. //
  5. // Derived from MirrorKit.
  6. // Created by Tanner on 6/29/15.
  7. // Copyright (c) 2015 Tanner Bennett. All rights reserved.
  8. //
  9. #import "FLEXMirror.h"
  10. #import "FLEXProperty.h"
  11. #import "FLEXMethod.h"
  12. #import "FLEXIvar.h"
  13. #import "FLEXProtocol.h"
  14. #import "FLEXUtility.h"
  15. #pragma mark FLEXMirror
  16. @implementation FLEXMirror
  17. - (id)init {
  18. [NSException
  19. raise:NSInternalInconsistencyException
  20. format:@"Class instance should not be created with -init"
  21. ];
  22. return nil;
  23. }
  24. #pragma mark Initialization
  25. + (instancetype)reflect:(id)objectOrClass {
  26. return [[self alloc] initWithValue:objectOrClass];
  27. }
  28. - (id)initWithValue:(id)value {
  29. NSParameterAssert(value);
  30. self = [super init];
  31. if (self) {
  32. _value = value;
  33. [self examine];
  34. }
  35. return self;
  36. }
  37. - (NSString *)description {
  38. NSString *type = self.isClass ? @"metaclass" : @"class";
  39. return [NSString
  40. stringWithFormat:@"<%@ %@=%@, %lu properties, %lu ivars, %lu methods, %lu protocols>",
  41. NSStringFromClass(self.class),
  42. type,
  43. self.className,
  44. (unsigned long)self.properties.count,
  45. (unsigned long)self.ivars.count,
  46. (unsigned long)self.methods.count,
  47. (unsigned long)self.protocols.count
  48. ];
  49. }
  50. - (void)examine {
  51. // cls is a metaclass if self.value is a class
  52. Class cls = object_getClass(self.value);
  53. unsigned int pcount, mcount, ivcount, pccount;
  54. objc_property_t *objcproperties = class_copyPropertyList(cls, &pcount);
  55. Protocol*__unsafe_unretained *procs = class_copyProtocolList(cls, &pccount);
  56. Method *objcmethods = class_copyMethodList(cls, &mcount);
  57. Ivar *objcivars = class_copyIvarList(cls, &ivcount);
  58. _className = NSStringFromClass(cls);
  59. _isClass = class_isMetaClass(cls); // or object_isClass(self.value)
  60. NSMutableArray *properties = [NSMutableArray new];
  61. for (int i = 0; i < pcount; i++)
  62. [properties addObject:[FLEXProperty property:objcproperties[i]]];
  63. _properties = properties;
  64. NSMutableArray *methods = [NSMutableArray new];
  65. for (int i = 0; i < mcount; i++)
  66. [methods addObject:[FLEXMethod method:objcmethods[i]]];
  67. _methods = methods;
  68. NSMutableArray *ivars = [NSMutableArray new];
  69. for (int i = 0; i < ivcount; i++)
  70. [ivars addObject:[FLEXIvar ivar:objcivars[i]]];
  71. _ivars = ivars;
  72. NSMutableArray *protocols = [NSMutableArray new];
  73. for (int i = 0; i < pccount; i++)
  74. [protocols addObject:[FLEXProtocol protocol:procs[i]]];
  75. _protocols = protocols;
  76. // Cleanup
  77. free(objcproperties);
  78. free(objcmethods);
  79. free(objcivars);
  80. free(procs);
  81. procs = NULL;
  82. }
  83. #pragma mark Misc
  84. - (FLEXMirror *)superMirror {
  85. return [FLEXMirror reflect:[self.value superclass]];
  86. }
  87. @end
  88. #pragma mark ExtendedMirror
  89. @implementation FLEXMirror (ExtendedMirror)
  90. - (id)filter:(NSArray *)array forName:(NSString *)name {
  91. NSPredicate *filter = [NSPredicate predicateWithFormat:@"%K = %@", @"name", name];
  92. return [array filteredArrayUsingPredicate:filter].firstObject;
  93. }
  94. - (FLEXMethod *)methodNamed:(NSString *)name {
  95. return [self filter:self.methods forName:name];
  96. }
  97. - (FLEXProperty *)propertyNamed:(NSString *)name {
  98. return [self filter:self.properties forName:name];
  99. }
  100. - (FLEXIvar *)ivarNamed:(NSString *)name {
  101. return [self filter:self.ivars forName:name];
  102. }
  103. - (FLEXProtocol *)protocolNamed:(NSString *)name {
  104. return [self filter:self.protocols forName:name];
  105. }
  106. @end