NSObject+MJClass.m 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. //
  2. // NSObject+MJClass.m
  3. // MJExtensionExample
  4. //
  5. // Created by MJ Lee on 15/8/11.
  6. // Copyright (c) 2015年 小码哥. All rights reserved.
  7. //
  8. #import "NSObject+MJClass.h"
  9. #import "NSObject+MJCoding.h"
  10. #import "NSObject+MJKeyValue.h"
  11. #import "MJFoundation.h"
  12. #import <objc/runtime.h>
  13. static const char MJAllowedPropertyNamesKey = '\0';
  14. static const char MJIgnoredPropertyNamesKey = '\0';
  15. static const char MJAllowedCodingPropertyNamesKey = '\0';
  16. static const char MJIgnoredCodingPropertyNamesKey = '\0';
  17. static NSMutableDictionary *allowedPropertyNamesDict_;
  18. static NSMutableDictionary *ignoredPropertyNamesDict_;
  19. static NSMutableDictionary *allowedCodingPropertyNamesDict_;
  20. static NSMutableDictionary *ignoredCodingPropertyNamesDict_;
  21. @implementation NSObject (MJClass)
  22. + (void)load
  23. {
  24. allowedPropertyNamesDict_ = [NSMutableDictionary dictionary];
  25. ignoredPropertyNamesDict_ = [NSMutableDictionary dictionary];
  26. allowedCodingPropertyNamesDict_ = [NSMutableDictionary dictionary];
  27. ignoredCodingPropertyNamesDict_ = [NSMutableDictionary dictionary];
  28. }
  29. + (NSMutableDictionary *)dictForKey:(const void *)key
  30. {
  31. @synchronized (self) {
  32. if (key == &MJAllowedPropertyNamesKey) return allowedPropertyNamesDict_;
  33. if (key == &MJIgnoredPropertyNamesKey) return ignoredPropertyNamesDict_;
  34. if (key == &MJAllowedCodingPropertyNamesKey) return allowedCodingPropertyNamesDict_;
  35. if (key == &MJIgnoredCodingPropertyNamesKey) return ignoredCodingPropertyNamesDict_;
  36. return nil;
  37. }
  38. }
  39. + (void)mj_enumerateClasses:(MJClassesEnumeration)enumeration
  40. {
  41. // 1.没有block就直接返回
  42. if (enumeration == nil) return;
  43. // 2.停止遍历的标记
  44. BOOL stop = NO;
  45. // 3.当前正在遍历的类
  46. Class c = self;
  47. // 4.开始遍历每一个类
  48. while (c && !stop) {
  49. // 4.1.执行操作
  50. enumeration(c, &stop);
  51. // 4.2.获得父类
  52. c = class_getSuperclass(c);
  53. if ([MJFoundation isClassFromFoundation:c]) break;
  54. }
  55. }
  56. + (void)mj_enumerateAllClasses:(MJClassesEnumeration)enumeration
  57. {
  58. // 1.没有block就直接返回
  59. if (enumeration == nil) return;
  60. // 2.停止遍历的标记
  61. BOOL stop = NO;
  62. // 3.当前正在遍历的类
  63. Class c = self;
  64. // 4.开始遍历每一个类
  65. while (c && !stop) {
  66. // 4.1.执行操作
  67. enumeration(c, &stop);
  68. // 4.2.获得父类
  69. c = class_getSuperclass(c);
  70. }
  71. }
  72. #pragma mark - 属性黑名单配置
  73. + (void)mj_setupIgnoredPropertyNames:(MJIgnoredPropertyNames)ignoredPropertyNames
  74. {
  75. [self mj_setupBlockReturnValue:ignoredPropertyNames key:&MJIgnoredPropertyNamesKey];
  76. }
  77. + (NSMutableArray *)mj_totalIgnoredPropertyNames
  78. {
  79. return [self mj_totalObjectsWithSelector:@selector(mj_ignoredPropertyNames) key:&MJIgnoredPropertyNamesKey];
  80. }
  81. #pragma mark - 归档属性黑名单配置
  82. + (void)mj_setupIgnoredCodingPropertyNames:(MJIgnoredCodingPropertyNames)ignoredCodingPropertyNames
  83. {
  84. [self mj_setupBlockReturnValue:ignoredCodingPropertyNames key:&MJIgnoredCodingPropertyNamesKey];
  85. }
  86. + (NSMutableArray *)mj_totalIgnoredCodingPropertyNames
  87. {
  88. return [self mj_totalObjectsWithSelector:@selector(mj_ignoredCodingPropertyNames) key:&MJIgnoredCodingPropertyNamesKey];
  89. }
  90. #pragma mark - 属性白名单配置
  91. + (void)mj_setupAllowedPropertyNames:(MJAllowedPropertyNames)allowedPropertyNames;
  92. {
  93. [self mj_setupBlockReturnValue:allowedPropertyNames key:&MJAllowedPropertyNamesKey];
  94. }
  95. + (NSMutableArray *)mj_totalAllowedPropertyNames
  96. {
  97. return [self mj_totalObjectsWithSelector:@selector(mj_allowedPropertyNames) key:&MJAllowedPropertyNamesKey];
  98. }
  99. #pragma mark - 归档属性白名单配置
  100. + (void)mj_setupAllowedCodingPropertyNames:(MJAllowedCodingPropertyNames)allowedCodingPropertyNames
  101. {
  102. [self mj_setupBlockReturnValue:allowedCodingPropertyNames key:&MJAllowedCodingPropertyNamesKey];
  103. }
  104. + (NSMutableArray *)mj_totalAllowedCodingPropertyNames
  105. {
  106. return [self mj_totalObjectsWithSelector:@selector(mj_allowedCodingPropertyNames) key:&MJAllowedCodingPropertyNamesKey];
  107. }
  108. #pragma mark - block和方法处理:存储block的返回值
  109. + (void)mj_setupBlockReturnValue:(id (^)())block key:(const char *)key
  110. {
  111. if (block) {
  112. objc_setAssociatedObject(self, key, block(), OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  113. } else {
  114. objc_setAssociatedObject(self, key, nil, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  115. }
  116. // 清空数据
  117. [[self dictForKey:key] removeAllObjects];
  118. }
  119. + (NSMutableArray *)mj_totalObjectsWithSelector:(SEL)selector key:(const char *)key
  120. {
  121. NSMutableArray *array = [self dictForKey:key][NSStringFromClass(self)];
  122. if (array) return array;
  123. // 创建、存储
  124. [self dictForKey:key][NSStringFromClass(self)] = array = [NSMutableArray array];
  125. if ([self respondsToSelector:selector]) {
  126. #pragma clang diagnostic push
  127. #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
  128. NSArray *subArray = [self performSelector:selector];
  129. #pragma clang diagnostic pop
  130. if (subArray) {
  131. [array addObjectsFromArray:subArray];
  132. }
  133. }
  134. [self mj_enumerateAllClasses:^(__unsafe_unretained Class c, BOOL *stop) {
  135. NSArray *subArray = objc_getAssociatedObject(c, key);
  136. [array addObjectsFromArray:subArray];
  137. }];
  138. return array;
  139. }
  140. @end