FLEXProperty.m 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  1. //
  2. // FLEXProperty.m
  3. // FLEX
  4. //
  5. // Derived from MirrorKit.
  6. // Created by Tanner on 6/30/15.
  7. // Copyright (c) 2015 Tanner Bennett. All rights reserved.
  8. //
  9. #import "FLEXProperty.h"
  10. #import "FLEXPropertyAttributes.h"
  11. #import "FLEXMethodBase.h"
  12. #import "FLEXRuntimeUtility.h"
  13. #include <dlfcn.h>
  14. @interface FLEXProperty () {
  15. NSString *_flex_description;
  16. }
  17. @property (nonatomic ) BOOL uniqueCheckFlag;
  18. @property (nonatomic, readonly) Class cls;
  19. @end
  20. @implementation FLEXProperty
  21. @synthesize multiple = _multiple;
  22. @synthesize imageName = _imageName;
  23. #pragma mark Initializers
  24. - (id)init {
  25. [NSException
  26. raise:NSInternalInconsistencyException
  27. format:@"Class instance should not be created with -init"
  28. ];
  29. return nil;
  30. }
  31. + (instancetype)property:(objc_property_t)property {
  32. return [[self alloc] initWithProperty:property onClass:nil];
  33. }
  34. + (instancetype)property:(objc_property_t)property onClass:(Class)cls {
  35. return [[self alloc] initWithProperty:property onClass:cls];
  36. }
  37. + (instancetype)named:(NSString *)name onClass:(Class)cls {
  38. return [self property:class_getProperty(cls, name.UTF8String) onClass:cls];
  39. }
  40. + (instancetype)propertyWithName:(NSString *)name attributes:(FLEXPropertyAttributes *)attributes {
  41. return [[self alloc] initWithName:name attributes:attributes];
  42. }
  43. - (id)initWithProperty:(objc_property_t)property onClass:(Class)cls {
  44. NSParameterAssert(property);
  45. self = [super init];
  46. if (self) {
  47. _objc_property = property;
  48. _attributes = [FLEXPropertyAttributes attributesForProperty:property];
  49. _name = @(property_getName(property));
  50. _cls = cls;
  51. if (!_attributes) [NSException raise:NSInternalInconsistencyException format:@"Error retrieving property attributes"];
  52. if (!_name) [NSException raise:NSInternalInconsistencyException format:@"Error retrieving property name"];
  53. [self examine];
  54. }
  55. return self;
  56. }
  57. - (id)initWithName:(NSString *)name attributes:(FLEXPropertyAttributes *)attributes {
  58. NSParameterAssert(name); NSParameterAssert(attributes);
  59. self = [super init];
  60. if (self) {
  61. _attributes = attributes;
  62. _name = name;
  63. [self examine];
  64. }
  65. return self;
  66. }
  67. #pragma mark Private
  68. - (void)examine {
  69. _type = (FLEXTypeEncoding)[self.attributes.typeEncoding characterAtIndex:0];
  70. _likelyGetter = self.attributes.customGetter ?: NSSelectorFromString(self.name);
  71. _likelySetter = self.attributes.customSetter ?: NSSelectorFromString([NSString
  72. stringWithFormat:@"set%c%@:",
  73. (char)toupper([self.name characterAtIndex:0]),
  74. [self.name substringFromIndex:1]
  75. ]);
  76. if (_cls) {
  77. _likelySetterExists = [_cls instancesRespondToSelector:_likelySetter];
  78. _likelyGetterExists = [_cls instancesRespondToSelector:_likelyGetter];
  79. _isClassProperty = class_isMetaClass(_cls);
  80. }
  81. }
  82. #pragma mark Overrides
  83. - (NSString *)description {
  84. if (!_flex_description) {
  85. NSString *readableType = [FLEXRuntimeUtility readableTypeForEncoding:self.attributes.typeEncoding];
  86. _flex_description = [FLEXRuntimeUtility appendName:self.name toType:readableType];
  87. }
  88. return _flex_description;
  89. }
  90. - (NSString *)debugDescription {
  91. return [NSString stringWithFormat:@"<%@ name=%@, property=%p, attributes:\n\t%@\n>",
  92. NSStringFromClass(self.class), self.name, self.objc_property, self.attributes];
  93. }
  94. #pragma mark Public
  95. - (objc_property_attribute_t *)copyAttributesList:(unsigned int *)attributesCount {
  96. if (self.objc_property) {
  97. return property_copyAttributeList(self.objc_property, attributesCount);
  98. } else {
  99. return [self.attributes copyAttributesList:attributesCount];
  100. }
  101. }
  102. - (void)replacePropertyOnClass:(Class)cls {
  103. class_replaceProperty(cls, self.name.UTF8String, self.attributes.list, (unsigned int)self.attributes.count);
  104. }
  105. - (void)computeSymbolInfo:(BOOL)forceBundle {
  106. if ((!_multiple || !_uniqueCheckFlag) && _cls) {
  107. _multiple = _objc_property != class_getProperty(_cls, self.name.UTF8String);
  108. if (_multiple || forceBundle) {
  109. Dl_info exeInfo;
  110. dladdr(_objc_property, &exeInfo);
  111. NSString *path = @(exeInfo.dli_fname).stringByDeletingLastPathComponent;
  112. _imageName = [NSBundle bundleWithPath:path].executablePath.lastPathComponent;
  113. }
  114. }
  115. }
  116. - (BOOL)multiple {
  117. [self computeSymbolInfo:NO];
  118. return _multiple;
  119. }
  120. - (NSString *)imageName {
  121. [self computeSymbolInfo:YES];
  122. return _imageName;
  123. }
  124. - (id)getValue:(id)target {
  125. return [FLEXRuntimeUtility valueForProperty:self.objc_property onObject:target];
  126. }
  127. - (id)getPotentiallyUnboxedValue:(id)target {
  128. return [FLEXRuntimeUtility
  129. potentiallyUnwrapBoxedPointer:[self getValue:target]
  130. type:self.attributes.typeEncoding.UTF8String
  131. ];
  132. }
  133. #pragma mark Suggested getters and setters
  134. - (FLEXMethodBase *)getterWithImplementation:(IMP)implementation {
  135. NSString *types = [NSString stringWithFormat:@"%@%s%s", self.attributes.typeEncoding, @encode(id), @encode(SEL)];
  136. NSString *name = [NSString stringWithFormat:@"%@", self.name];
  137. FLEXMethodBase *getter = [FLEXMethodBase buildMethodNamed:name withTypes:types implementation:implementation];
  138. return getter;
  139. }
  140. - (FLEXMethodBase *)setterWithImplementation:(IMP)implementation {
  141. NSString *types = [NSString stringWithFormat:@"%s%s%s%@", @encode(void), @encode(id), @encode(SEL), self.attributes.typeEncoding];
  142. NSString *name = [NSString stringWithFormat:@"set%@:", self.name.capitalizedString];
  143. FLEXMethodBase *setter = [FLEXMethodBase buildMethodNamed:name withTypes:types implementation:implementation];
  144. return setter;
  145. }
  146. @end