FLEXPropertyAttributes.m 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  1. //
  2. // FLEXPropertyAttributes.m
  3. // FLEX
  4. //
  5. // Derived from MirrorKit.
  6. // Created by Tanner on 7/5/15.
  7. // Copyright (c) 2015 Tanner Bennett. All rights reserved.
  8. //
  9. #import "FLEXPropertyAttributes.h"
  10. #import "FLEXRuntimeUtility.h"
  11. #import "NSString+ObjcRuntime.h"
  12. #import "NSDictionary+ObjcRuntime.h"
  13. #pragma mark FLEXPropertyAttributes
  14. @interface FLEXPropertyAttributes ()
  15. @property (nonatomic) NSString *backingIvar;
  16. @property (nonatomic) NSString *typeEncoding;
  17. @property (nonatomic) NSString *oldTypeEncoding;
  18. @property (nonatomic) SEL customGetter;
  19. @property (nonatomic) SEL customSetter;
  20. @property (nonatomic) BOOL isReadOnly;
  21. @property (nonatomic) BOOL isCopy;
  22. @property (nonatomic) BOOL isRetained;
  23. @property (nonatomic) BOOL isNonatomic;
  24. @property (nonatomic) BOOL isDynamic;
  25. @property (nonatomic) BOOL isWeak;
  26. @property (nonatomic) BOOL isGarbageCollectable;
  27. @end
  28. @implementation FLEXPropertyAttributes
  29. @synthesize list = _list;
  30. #pragma mark Initializers
  31. + (instancetype)attributesForProperty:(objc_property_t)property {
  32. return [self attributesFromDictionary:[NSDictionary attributesDictionaryForProperty:property]];
  33. }
  34. + (instancetype)attributesFromDictionary:(NSDictionary *)attributes {
  35. return [[self alloc] initWithAttributesDictionary:attributes];
  36. }
  37. - (id)initWithAttributesDictionary:(NSDictionary *)attributes {
  38. NSParameterAssert(attributes);
  39. self = [super init];
  40. if (self) {
  41. _dictionary = attributes;
  42. _string = attributes.propertyAttributesString;
  43. _count = attributes.count;
  44. _typeEncoding = attributes[kFLEXPropertyAttributeKeyTypeEncoding];
  45. _backingIvar = attributes[kFLEXPropertyAttributeKeyBackingIvarName];
  46. _oldTypeEncoding = attributes[kFLEXPropertyAttributeKeyOldStyleTypeEncoding];
  47. _customGetter = NSSelectorFromString(attributes[kFLEXPropertyAttributeKeyCustomGetter]);
  48. _customSetter = NSSelectorFromString(attributes[kFLEXPropertyAttributeKeyCustomSetter]);
  49. _isReadOnly = attributes[kFLEXPropertyAttributeKeyReadOnly] != nil;
  50. _isCopy = attributes[kFLEXPropertyAttributeKeyCopy] != nil;
  51. _isRetained = attributes[kFLEXPropertyAttributeKeyRetain] != nil;
  52. _isNonatomic = attributes[kFLEXPropertyAttributeKeyNonAtomic] != nil;
  53. _isWeak = attributes[kFLEXPropertyAttributeKeyWeak] != nil;
  54. _isGarbageCollectable = attributes[kFLEXPropertyAttributeKeyGarbageCollectable] != nil;
  55. }
  56. return self;
  57. }
  58. #pragma mark Misc
  59. - (NSString *)description {
  60. return [NSString
  61. stringWithFormat:@"<%@ \"%@\", ivar=%@, readonly=%d, nonatomic=%d, getter=%@, setter=%@>",
  62. NSStringFromClass(self.class),
  63. self.string,
  64. self.backingIvar ?: @"none",
  65. self.isReadOnly,
  66. self.isNonatomic,
  67. NSStringFromSelector(self.customGetter) ?: @"none",
  68. NSStringFromSelector(self.customSetter) ?: @"none"
  69. ];
  70. }
  71. - (objc_property_attribute_t *)copyAttributesList:(unsigned int *)attributesCount {
  72. NSDictionary *attrs = self.string.propertyAttributes;
  73. objc_property_attribute_t *propertyAttributes = malloc(attrs.count * sizeof(objc_property_attribute_t));
  74. if (attributesCount) {
  75. *attributesCount = (unsigned int)attrs.count;
  76. }
  77. NSUInteger i = 0;
  78. for (NSString *key in attrs.allKeys) {
  79. FLEXPropertyAttribute c = (FLEXPropertyAttribute)[key characterAtIndex:0];
  80. switch (c) {
  81. case FLEXPropertyAttributeTypeEncoding: {
  82. objc_property_attribute_t pa = {
  83. kFLEXPropertyAttributeKeyTypeEncoding.UTF8String,
  84. self.typeEncoding.UTF8String
  85. };
  86. propertyAttributes[i] = pa;
  87. break;
  88. }
  89. case FLEXPropertyAttributeBackingIvarName: {
  90. objc_property_attribute_t pa = {
  91. kFLEXPropertyAttributeKeyBackingIvarName.UTF8String,
  92. self.backingIvar.UTF8String
  93. };
  94. propertyAttributes[i] = pa;
  95. break;
  96. }
  97. case FLEXPropertyAttributeCopy: {
  98. objc_property_attribute_t pa = {kFLEXPropertyAttributeKeyCopy.UTF8String, ""};
  99. propertyAttributes[i] = pa;
  100. break;
  101. }
  102. case FLEXPropertyAttributeCustomGetter: {
  103. objc_property_attribute_t pa = {
  104. kFLEXPropertyAttributeKeyCustomGetter.UTF8String,
  105. NSStringFromSelector(self.customGetter).UTF8String ?: ""
  106. };
  107. propertyAttributes[i] = pa;
  108. break;
  109. }
  110. case FLEXPropertyAttributeCustomSetter: {
  111. objc_property_attribute_t pa = {
  112. kFLEXPropertyAttributeKeyCustomSetter.UTF8String,
  113. NSStringFromSelector(self.customSetter).UTF8String ?: ""
  114. };
  115. propertyAttributes[i] = pa;
  116. break;
  117. }
  118. case FLEXPropertyAttributeDynamic: {
  119. objc_property_attribute_t pa = {kFLEXPropertyAttributeKeyDynamic.UTF8String, ""};
  120. propertyAttributes[i] = pa;
  121. break;
  122. }
  123. case FLEXPropertyAttributeGarbageCollectible: {
  124. objc_property_attribute_t pa = {kFLEXPropertyAttributeKeyGarbageCollectable.UTF8String, ""};
  125. propertyAttributes[i] = pa;
  126. break;
  127. }
  128. case FLEXPropertyAttributeNonAtomic: {
  129. objc_property_attribute_t pa = {kFLEXPropertyAttributeKeyNonAtomic.UTF8String, ""};
  130. propertyAttributes[i] = pa;
  131. break;
  132. }
  133. case FLEXPropertyAttributeOldTypeEncoding: {
  134. objc_property_attribute_t pa = {
  135. kFLEXPropertyAttributeKeyOldStyleTypeEncoding.UTF8String,
  136. self.oldTypeEncoding.UTF8String ?: ""
  137. };
  138. propertyAttributes[i] = pa;
  139. break;
  140. }
  141. case FLEXPropertyAttributeReadOnly: {
  142. objc_property_attribute_t pa = {kFLEXPropertyAttributeKeyReadOnly.UTF8String, ""};
  143. propertyAttributes[i] = pa;
  144. break;
  145. }
  146. case FLEXPropertyAttributeRetain: {
  147. objc_property_attribute_t pa = {kFLEXPropertyAttributeKeyRetain.UTF8String, ""};
  148. propertyAttributes[i] = pa;
  149. break;
  150. }
  151. case FLEXPropertyAttributeWeak: {
  152. objc_property_attribute_t pa = {kFLEXPropertyAttributeKeyWeak.UTF8String, ""};
  153. propertyAttributes[i] = pa;
  154. break;
  155. }
  156. }
  157. i++;
  158. }
  159. return propertyAttributes;
  160. }
  161. - (objc_property_attribute_t *)list {
  162. if (!_list) {
  163. _list = [self copyAttributesList:nil];
  164. }
  165. return _list;
  166. }
  167. - (void)dealloc {
  168. if (_list) {
  169. free(_list);
  170. _list = nil;
  171. }
  172. }
  173. #pragma mark Copying
  174. - (id)copyWithZone:(NSZone *)zone {
  175. return [[FLEXPropertyAttributes class] attributesFromDictionary:self.dictionary];
  176. }
  177. - (id)mutableCopyWithZone:(NSZone *)zone {
  178. return [[FLEXMutablePropertyAttributes class] attributesFromDictionary:self.dictionary];
  179. }
  180. @end
  181. #pragma mark FLEXMutablePropertyAttributes
  182. @interface FLEXMutablePropertyAttributes ()
  183. @property (nonatomic) BOOL countDelta;
  184. @property (nonatomic) BOOL stringDelta;
  185. @property (nonatomic) BOOL dictDelta;
  186. @property (nonatomic) BOOL listDelta;
  187. @end
  188. #define PropertyWithDeltaFlag(type, name, Name) @dynamic name; \
  189. - (void)set ## Name:(type)name { \
  190. if (name != _ ## name) { \
  191. _countDelta = _stringDelta = _dictDelta = _listDelta = YES; \
  192. _ ## name = name; \
  193. } \
  194. }
  195. @implementation FLEXMutablePropertyAttributes
  196. PropertyWithDeltaFlag(NSString *, backingIvar, BackingIvar);
  197. PropertyWithDeltaFlag(NSString *, typeEncoding, TypeEncoding);
  198. PropertyWithDeltaFlag(NSString *, oldTypeEncoding, OldTypeEncoding);
  199. PropertyWithDeltaFlag(SEL, customGetter, CustomGetter);
  200. PropertyWithDeltaFlag(SEL, customSetter, CustomSetter);
  201. PropertyWithDeltaFlag(BOOL, isReadOnly, IsReadOnly);
  202. PropertyWithDeltaFlag(BOOL, isCopy, IsCopy);
  203. PropertyWithDeltaFlag(BOOL, isRetained, IsRetained);
  204. PropertyWithDeltaFlag(BOOL, isNonatomic, IsNonatomic);
  205. PropertyWithDeltaFlag(BOOL, isDynamic, IsDynamic);
  206. PropertyWithDeltaFlag(BOOL, isWeak, IsWeak);
  207. PropertyWithDeltaFlag(BOOL, isGarbageCollectable, IsGarbageCollectable);
  208. + (instancetype)attributes {
  209. return [self new];
  210. }
  211. - (void)setTypeEncodingChar:(char)type {
  212. self.typeEncoding = [NSString stringWithFormat:@"%c", type];
  213. }
  214. - (NSUInteger)count {
  215. // Recalculate attribute count after mutations
  216. if (self.countDelta) {
  217. self.countDelta = NO;
  218. _count = self.dictionary.count;
  219. }
  220. return _count;
  221. }
  222. - (objc_property_attribute_t *)list {
  223. // Regenerate list after mutations
  224. if (self.listDelta) {
  225. self.listDelta = NO;
  226. if (_list) {
  227. free(_list);
  228. _list = nil;
  229. }
  230. }
  231. // Super will generate the list if it isn't set
  232. return super.list;
  233. }
  234. - (NSString *)string {
  235. // Regenerate string after mutations
  236. if (self.stringDelta || !_string) {
  237. self.stringDelta = NO;
  238. _string = self.dictionary.propertyAttributesString;
  239. }
  240. return _string;
  241. }
  242. - (NSDictionary *)dictionary {
  243. // Regenerate dictionary after mutations
  244. if (self.dictDelta || !_dictionary) {
  245. // _stringa nd _dictionary depend on each other,
  246. // so we must generate ONE by hand using our properties.
  247. // We arbitrarily choose to generate the dictionary.
  248. NSMutableDictionary *attrs = [NSMutableDictionary new];
  249. if (self.typeEncoding)
  250. attrs[kFLEXPropertyAttributeKeyTypeEncoding] = self.typeEncoding;
  251. if (self.backingIvar)
  252. attrs[kFLEXPropertyAttributeKeyBackingIvarName] = self.backingIvar;
  253. if (self.oldTypeEncoding)
  254. attrs[kFLEXPropertyAttributeKeyOldStyleTypeEncoding] = self.oldTypeEncoding;
  255. if (self.customGetter)
  256. attrs[kFLEXPropertyAttributeKeyCustomGetter] = NSStringFromSelector(self.customGetter);
  257. if (self.customSetter)
  258. attrs[kFLEXPropertyAttributeKeyCustomSetter] = NSStringFromSelector(self.customSetter);
  259. if (self.isReadOnly) attrs[kFLEXPropertyAttributeKeyReadOnly] = @YES;
  260. if (self.isCopy) attrs[kFLEXPropertyAttributeKeyCopy] = @YES;
  261. if (self.isRetained) attrs[kFLEXPropertyAttributeKeyRetain] = @YES;
  262. if (self.isNonatomic) attrs[kFLEXPropertyAttributeKeyNonAtomic] = @YES;
  263. if (self.isDynamic) attrs[kFLEXPropertyAttributeKeyDynamic] = @YES;
  264. if (self.isWeak) attrs[kFLEXPropertyAttributeKeyWeak] = @YES;
  265. if (self.isGarbageCollectable) attrs[kFLEXPropertyAttributeKeyGarbageCollectable] = @YES;
  266. _dictionary = attrs.copy;
  267. }
  268. return _dictionary;
  269. }
  270. @end