NSObject+MJClass.m 5.6 KB

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