FLEXPropertyAttributes.m 13 KB

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