FLEXPropertyAttributes.m 11 KB

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