JastorRuntimeHelper.m 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. #import <objc/runtime.h>
  2. #import "JastorRuntimeHelper.h"
  3. #import "Jastor.h"
  4. static const char *property_getTypeName(objc_property_t property) {
  5. const char *attributes = property_getAttributes(property);
  6. char buffer[1 + strlen(attributes)];
  7. strcpy(buffer, attributes);
  8. char *state = buffer, *attribute;
  9. while ((attribute = strsep(&state, ",")) != NULL) {
  10. if (attribute[0] == 'T') {
  11. size_t len = strlen(attribute);
  12. attribute[len - 1] = '\0';
  13. return (const char *)[[NSData dataWithBytes:(attribute + 3) length:len - 2] bytes];
  14. }
  15. }
  16. return "@";
  17. }
  18. @implementation JastorRuntimeHelper
  19. static NSMutableDictionary *propertyListByClass;
  20. static NSMutableDictionary *propertyClassByClassAndPropertyName;
  21. + (BOOL)isPropertyReadOnly:(Class)klass propertyName:(NSString*)propertyName{
  22. const char * type = property_getAttributes(class_getProperty(klass, [propertyName UTF8String]));
  23. NSString * typeString = [NSString stringWithUTF8String:type];
  24. NSArray * attributes = [typeString componentsSeparatedByString:@","];
  25. NSString * typeAttribute = [attributes objectAtIndex:1];
  26. return [typeAttribute rangeOfString:@"R"].length > 0;
  27. }
  28. + (NSArray *)propertyNames:(Class)klass {
  29. if (klass == [Jastor class]) {
  30. return [NSArray array];
  31. }
  32. if (!propertyListByClass) {
  33. propertyListByClass = [[NSMutableDictionary alloc] init];
  34. }
  35. NSString *className = NSStringFromClass(klass);
  36. NSArray *value = [propertyListByClass objectForKey:className];
  37. if (value) {
  38. return value;
  39. }
  40. NSMutableArray *propertyNamesArray = [NSMutableArray array];
  41. unsigned int propertyCount = 0;
  42. objc_property_t *properties = class_copyPropertyList(klass, &propertyCount);
  43. for (unsigned int i = 0; i < propertyCount; ++i) {
  44. objc_property_t property = properties[i];
  45. const char * name = property_getName(property);
  46. [propertyNamesArray addObject:[NSString stringWithUTF8String:name]];
  47. }
  48. free(properties);
  49. [propertyListByClass setObject:propertyNamesArray forKey:className];
  50. NSArray* arr = [JastorRuntimeHelper propertyNames:class_getSuperclass(klass)];
  51. [propertyNamesArray addObjectsFromArray:arr];
  52. return propertyNamesArray;
  53. }
  54. + (Class)propertyClassForPropertyName:(NSString *)propertyName ofClass:(Class)klass {
  55. if (!propertyClassByClassAndPropertyName) {
  56. propertyClassByClassAndPropertyName = [[NSMutableDictionary alloc] init];
  57. }
  58. NSString *key = [NSString stringWithFormat:@"%@:%@", NSStringFromClass(klass), propertyName];
  59. NSString *value = [propertyClassByClassAndPropertyName objectForKey:key];
  60. if (value) {
  61. return NSClassFromString(value);
  62. }
  63. unsigned int propertyCount = 0;
  64. objc_property_t *properties = class_copyPropertyList(klass, &propertyCount);
  65. const char * cPropertyName = [propertyName UTF8String];
  66. for (unsigned int i = 0; i < propertyCount; ++i) {
  67. objc_property_t property = properties[i];
  68. const char * name = property_getName(property);
  69. if (strcmp(cPropertyName, name) == 0) {
  70. free(properties);
  71. NSString *className = [NSString stringWithUTF8String:property_getTypeName(property)];
  72. [propertyClassByClassAndPropertyName setObject:className forKey:key];
  73. //we found the property - we need to free
  74. return NSClassFromString(className);
  75. }
  76. }
  77. free(properties);
  78. //this will support traversing the inheritance chain
  79. return [self propertyClassForPropertyName:propertyName ofClass:class_getSuperclass(klass)];
  80. }
  81. @end