/Classes/ISPropertyDescriptor.m

http://github.com/ilya-volkov/Introspection · Objective C · 149 lines · 118 code · 31 blank · 0 comment · 21 complexity · 940442c6d4894464b061bebf6d99f350 MD5 · raw file

  1. #import "ISPropertyDescriptor.h"
  2. #import "ISSetterSemanticsType.h"
  3. #import "ISInvalidStateException.h"
  4. #import "NSString+Extensions.h"
  5. #import "NSValue+Extensions.h"
  6. #import "NSInvocation+Extensions.h"
  7. @interface ISPropertyDescriptor ()
  8. - (void) parsePropertyAttributeDescription:(NSString*)description;
  9. - (void) setDefaultAttributeValues;
  10. @end
  11. @implementation ISPropertyDescriptor {
  12. @private
  13. objc_property_t property;
  14. BOOL isObjectType;
  15. NSString *attributesDescription;
  16. }
  17. @synthesize name;
  18. @synthesize backingVariable;
  19. @synthesize getter;
  20. @synthesize setter;
  21. @synthesize typeEncoding;
  22. @synthesize setterSemanticsType;
  23. @synthesize isReadOnly;
  24. @synthesize isNonAtomic;
  25. @synthesize isDynamic;
  26. @synthesize isWeakReference;
  27. @synthesize isEligibleForGarbageCollection;
  28. + (ISPropertyDescriptor*) descriptorForName:(NSString*)name inClass:(Class)class {
  29. objc_property_t property = class_getProperty(class, [name cStringUsingEncoding:NSASCIIStringEncoding]);
  30. if (property == nil)
  31. return nil;
  32. return [ISPropertyDescriptor descriptorForProperty:property];
  33. }
  34. + (ISPropertyDescriptor*) descriptorForName:(NSString*)name inProtocol:(Protocol*)protocol {
  35. objc_property_t property = protocol_getProperty(
  36. protocol, [name cStringUsingEncoding:NSASCIIStringEncoding], YES, YES
  37. );
  38. if (property == nil)
  39. return nil;
  40. return [ISPropertyDescriptor descriptorForProperty:property];
  41. }
  42. + (ISPropertyDescriptor*) descriptorForProperty:(objc_property_t)property {
  43. return [[ISPropertyDescriptor alloc] initWithProperty:property];
  44. }
  45. - (id) initWithProperty:(objc_property_t)property {
  46. self = [super init];
  47. if (self) {
  48. self->property = property;
  49. name = [NSString stringWithCString:property_getName(property) encoding:NSASCIIStringEncoding];
  50. [self parsePropertyAttributeDescription:
  51. [NSString stringWithCString:property_getAttributes(property) encoding:NSASCIIStringEncoding]
  52. ];
  53. }
  54. return self;
  55. }
  56. - (void) setValue:(NSValue*)value inObject:(id)object {
  57. if (isReadOnly)
  58. @throw [ISInvalidStateException exceptionWithReason:@"Can't set readonly property"];
  59. if (isObjectType) {
  60. [object performSelector:setter withObject:[value nonretainedObjectValue]];
  61. return;
  62. }
  63. NSInvocation* invocation = [NSInvocation invocationWithMethodSignature:[object methodSignatureForSelector:setter]];
  64. [invocation setSelector:setter];
  65. NSMutableData* dataValue = [[value dataValue] mutableCopy];
  66. [invocation setArgument:[dataValue mutableBytes] atIndex:2];
  67. [invocation invokeWithTarget:object];
  68. }
  69. - (NSValue*) getValueFromObject:(id)object {
  70. if (isObjectType)
  71. return [NSValue valueWithNonretainedObject:[object performSelector:getter]];
  72. NSInvocation* invocation = [NSInvocation
  73. invocationWithMethodSignature:[object methodSignatureForSelector:getter]
  74. ];
  75. [invocation setSelector:getter];
  76. [invocation invokeWithTarget:object];
  77. return [invocation getReturnValue];
  78. }
  79. - (void) setDefaultAttributeValues {
  80. getter = NSSelectorFromString(name);
  81. setter = NSSelectorFromString([NSString stringWithFormat:@"set%@:", [name camelcaseString]]);
  82. setterSemanticsType = ISAssignSetterSemanticsType;
  83. }
  84. - (void) parsePropertyAttributeDescription:(NSString*)description {
  85. [self setDefaultAttributeValues];
  86. attributesDescription = description;
  87. NSArray* attributes = [description componentsSeparatedByString:@","];
  88. for (NSString *attribute in attributes) {
  89. if ([attribute hasPrefix:@"T"])
  90. typeEncoding = [attribute substringFromIndex:1];
  91. if ([attribute isEqualToString:@"R"])
  92. isReadOnly = YES;
  93. if ([attribute isEqualToString:@"C"])
  94. setterSemanticsType = ISCopySetterSemanticsType;
  95. if ([attribute isEqualToString:@"&"])
  96. setterSemanticsType = ISRetainSetterSemanticsType;
  97. if ([attribute isEqualToString:@"N"])
  98. isNonAtomic = YES;
  99. if ([attribute hasPrefix:@"G"])
  100. getter = NSSelectorFromString([attribute substringFromIndex:1]);
  101. if ([attribute hasPrefix:@"S"])
  102. setter = NSSelectorFromString([attribute substringFromIndex:1]);
  103. if ([attribute isEqualToString:@"D"])
  104. isDynamic = YES;
  105. if ([attribute isEqualToString:@"W"])
  106. isWeakReference = YES;
  107. if ([attribute isEqualToString:@"P"])
  108. isEligibleForGarbageCollection = YES;
  109. if ([attribute hasPrefix:@"V"])
  110. backingVariable = [attribute substringFromIndex:1];
  111. }
  112. if (isReadOnly)
  113. setter = nil;
  114. isObjectType = [typeEncoding
  115. hasPrefix:[NSString stringWithCString:@encode(id) encoding:NSASCIIStringEncoding]
  116. ];
  117. }
  118. @end