123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377 |
- //
- // FLEXPropertyAttributes.m
- // FLEX
- //
- // Derived from MirrorKit.
- // Created by Tanner on 7/5/15.
- // Copyright (c) 2020 FLEX Team. All rights reserved.
- //
- #import "FLEXPropertyAttributes.h"
- #import "FLEXRuntimeUtility.h"
- #import "NSString+ObjcRuntime.h"
- #import "NSDictionary+ObjcRuntime.h"
- #pragma mark FLEXPropertyAttributes
- @interface FLEXPropertyAttributes ()
- @property (nonatomic) NSString *backingIvar;
- @property (nonatomic) NSString *typeEncoding;
- @property (nonatomic) NSString *oldTypeEncoding;
- @property (nonatomic) SEL customGetter;
- @property (nonatomic) SEL customSetter;
- @property (nonatomic) BOOL isReadOnly;
- @property (nonatomic) BOOL isCopy;
- @property (nonatomic) BOOL isRetained;
- @property (nonatomic) BOOL isNonatomic;
- @property (nonatomic) BOOL isDynamic;
- @property (nonatomic) BOOL isWeak;
- @property (nonatomic) BOOL isGarbageCollectable;
- - (NSString *)buildFullDeclaration;
- @end
- @implementation FLEXPropertyAttributes
- @synthesize list = _list;
- #pragma mark Initializers
- + (instancetype)attributesForProperty:(objc_property_t)property {
- return [self attributesFromDictionary:[NSDictionary attributesDictionaryForProperty:property]];
- }
- + (instancetype)attributesFromDictionary:(NSDictionary *)attributes {
- return [[self alloc] initWithAttributesDictionary:attributes];
- }
- - (id)initWithAttributesDictionary:(NSDictionary *)attributes {
- NSParameterAssert(attributes);
-
- self = [super init];
- if (self) {
- _dictionary = attributes;
- _string = attributes.propertyAttributesString;
- _count = attributes.count;
- _typeEncoding = attributes[kFLEXPropertyAttributeKeyTypeEncoding];
- _backingIvar = attributes[kFLEXPropertyAttributeKeyBackingIvarName];
- _oldTypeEncoding = attributes[kFLEXPropertyAttributeKeyOldStyleTypeEncoding];
- _customGetterString = attributes[kFLEXPropertyAttributeKeyCustomGetter];
- _customSetterString = attributes[kFLEXPropertyAttributeKeyCustomSetter];
- _customGetter = NSSelectorFromString(_customGetterString);
- _customSetter = NSSelectorFromString(_customSetterString);
- _isReadOnly = attributes[kFLEXPropertyAttributeKeyReadOnly] != nil;
- _isCopy = attributes[kFLEXPropertyAttributeKeyCopy] != nil;
- _isRetained = attributes[kFLEXPropertyAttributeKeyRetain] != nil;
- _isNonatomic = attributes[kFLEXPropertyAttributeKeyNonAtomic] != nil;
- _isWeak = attributes[kFLEXPropertyAttributeKeyWeak] != nil;
- _isGarbageCollectable = attributes[kFLEXPropertyAttributeKeyGarbageCollectable] != nil;
- _fullDeclaration = [self buildFullDeclaration];
- }
-
- return self;
- }
- #pragma mark Misc
- - (NSString *)description {
- return [NSString
- stringWithFormat:@"<%@ \"%@\", ivar=%@, readonly=%d, nonatomic=%d, getter=%@, setter=%@>",
- NSStringFromClass(self.class),
- self.string,
- self.backingIvar ?: @"none",
- self.isReadOnly,
- self.isNonatomic,
- NSStringFromSelector(self.customGetter) ?: @"none",
- NSStringFromSelector(self.customSetter) ?: @"none"
- ];
- }
- - (objc_property_attribute_t *)copyAttributesList:(unsigned int *)attributesCount {
- NSDictionary *attrs = self.string.propertyAttributes;
- objc_property_attribute_t *propertyAttributes = malloc(attrs.count * sizeof(objc_property_attribute_t));
- if (attributesCount) {
- *attributesCount = (unsigned int)attrs.count;
- }
-
- NSUInteger i = 0;
- for (NSString *key in attrs.allKeys) {
- FLEXPropertyAttribute c = (FLEXPropertyAttribute)[key characterAtIndex:0];
- switch (c) {
- case FLEXPropertyAttributeTypeEncoding: {
- objc_property_attribute_t pa = {
- kFLEXPropertyAttributeKeyTypeEncoding.UTF8String,
- self.typeEncoding.UTF8String
- };
- propertyAttributes[i] = pa;
- break;
- }
- case FLEXPropertyAttributeBackingIvarName: {
- objc_property_attribute_t pa = {
- kFLEXPropertyAttributeKeyBackingIvarName.UTF8String,
- self.backingIvar.UTF8String
- };
- propertyAttributes[i] = pa;
- break;
- }
- case FLEXPropertyAttributeCopy: {
- objc_property_attribute_t pa = {kFLEXPropertyAttributeKeyCopy.UTF8String, ""};
- propertyAttributes[i] = pa;
- break;
- }
- case FLEXPropertyAttributeCustomGetter: {
- objc_property_attribute_t pa = {
- kFLEXPropertyAttributeKeyCustomGetter.UTF8String,
- NSStringFromSelector(self.customGetter).UTF8String ?: ""
- };
- propertyAttributes[i] = pa;
- break;
- }
- case FLEXPropertyAttributeCustomSetter: {
- objc_property_attribute_t pa = {
- kFLEXPropertyAttributeKeyCustomSetter.UTF8String,
- NSStringFromSelector(self.customSetter).UTF8String ?: ""
- };
- propertyAttributes[i] = pa;
- break;
- }
- case FLEXPropertyAttributeDynamic: {
- objc_property_attribute_t pa = {kFLEXPropertyAttributeKeyDynamic.UTF8String, ""};
- propertyAttributes[i] = pa;
- break;
- }
- case FLEXPropertyAttributeGarbageCollectible: {
- objc_property_attribute_t pa = {kFLEXPropertyAttributeKeyGarbageCollectable.UTF8String, ""};
- propertyAttributes[i] = pa;
- break;
- }
- case FLEXPropertyAttributeNonAtomic: {
- objc_property_attribute_t pa = {kFLEXPropertyAttributeKeyNonAtomic.UTF8String, ""};
- propertyAttributes[i] = pa;
- break;
- }
- case FLEXPropertyAttributeOldTypeEncoding: {
- objc_property_attribute_t pa = {
- kFLEXPropertyAttributeKeyOldStyleTypeEncoding.UTF8String,
- self.oldTypeEncoding.UTF8String ?: ""
- };
- propertyAttributes[i] = pa;
- break;
- }
- case FLEXPropertyAttributeReadOnly: {
- objc_property_attribute_t pa = {kFLEXPropertyAttributeKeyReadOnly.UTF8String, ""};
- propertyAttributes[i] = pa;
- break;
- }
- case FLEXPropertyAttributeRetain: {
- objc_property_attribute_t pa = {kFLEXPropertyAttributeKeyRetain.UTF8String, ""};
- propertyAttributes[i] = pa;
- break;
- }
- case FLEXPropertyAttributeWeak: {
- objc_property_attribute_t pa = {kFLEXPropertyAttributeKeyWeak.UTF8String, ""};
- propertyAttributes[i] = pa;
- break;
- }
- }
- i++;
- }
-
- return propertyAttributes;
- }
- - (objc_property_attribute_t *)list {
- if (!_list) {
- _list = [self copyAttributesList:nil];
- }
- return _list;
- }
- - (NSString *)buildFullDeclaration {
- NSMutableString *decl = [NSMutableString new];
- [decl appendFormat:@"%@, ", _isNonatomic ? @"nonatomic" : @"atomic"];
- [decl appendFormat:@"%@, ", _isReadOnly ? @"readonly" : @"readwrite"];
- BOOL noExplicitMemorySemantics = YES;
- if (_isCopy) { noExplicitMemorySemantics = NO;
- [decl appendString:@"copy, "];
- }
- if (_isRetained) { noExplicitMemorySemantics = NO;
- [decl appendString:@"strong, "];
- }
- if (_isWeak) { noExplicitMemorySemantics = NO;
- [decl appendString:@"weak, "];
- }
- if ([_typeEncoding hasPrefix:@"@"] && noExplicitMemorySemantics) {
- // *probably* strong if this is an object; strong is the default.
- [decl appendString:@"strong, "];
- } else if (noExplicitMemorySemantics) {
- // *probably* assign if this is not an object
- [decl appendString:@"assign, "];
- }
- if (_customGetter) {
- [decl appendFormat:@"getter=%@, ", NSStringFromSelector(_customGetter)];
- }
- if (_customSetter) {
- [decl appendFormat:@"setter=%@, ", NSStringFromSelector(_customSetter)];
- }
- [decl deleteCharactersInRange:NSMakeRange(decl.length-2, 2)];
- return decl.copy;
- }
- - (void)dealloc {
- if (_list) {
- free(_list);
- _list = nil;
- }
- }
- #pragma mark Copying
- - (id)copyWithZone:(NSZone *)zone {
- return [[FLEXPropertyAttributes class] attributesFromDictionary:self.dictionary];
- }
- - (id)mutableCopyWithZone:(NSZone *)zone {
- return [[FLEXMutablePropertyAttributes class] attributesFromDictionary:self.dictionary];
- }
- @end
- #pragma mark FLEXMutablePropertyAttributes
- @interface FLEXMutablePropertyAttributes ()
- @property (nonatomic) BOOL countDelta;
- @property (nonatomic) BOOL stringDelta;
- @property (nonatomic) BOOL dictDelta;
- @property (nonatomic) BOOL listDelta;
- @property (nonatomic) BOOL declDelta;
- @end
- #define PropertyWithDeltaFlag(type, name, Name) @dynamic name; \
- - (void)set ## Name:(type)name { \
- if (name != _ ## name) { \
- _countDelta = _stringDelta = _dictDelta = _listDelta = _declDelta = YES; \
- _ ## name = name; \
- } \
- }
- @implementation FLEXMutablePropertyAttributes
- PropertyWithDeltaFlag(NSString *, backingIvar, BackingIvar);
- PropertyWithDeltaFlag(NSString *, typeEncoding, TypeEncoding);
- PropertyWithDeltaFlag(NSString *, oldTypeEncoding, OldTypeEncoding);
- PropertyWithDeltaFlag(SEL, customGetter, CustomGetter);
- PropertyWithDeltaFlag(SEL, customSetter, CustomSetter);
- PropertyWithDeltaFlag(BOOL, isReadOnly, IsReadOnly);
- PropertyWithDeltaFlag(BOOL, isCopy, IsCopy);
- PropertyWithDeltaFlag(BOOL, isRetained, IsRetained);
- PropertyWithDeltaFlag(BOOL, isNonatomic, IsNonatomic);
- PropertyWithDeltaFlag(BOOL, isDynamic, IsDynamic);
- PropertyWithDeltaFlag(BOOL, isWeak, IsWeak);
- PropertyWithDeltaFlag(BOOL, isGarbageCollectable, IsGarbageCollectable);
- + (instancetype)attributes {
- return [self new];
- }
- - (void)setTypeEncodingChar:(char)type {
- self.typeEncoding = [NSString stringWithFormat:@"%c", type];
- }
- - (NSUInteger)count {
- // Recalculate attribute count after mutations
- if (self.countDelta) {
- self.countDelta = NO;
- _count = self.dictionary.count;
- }
- return _count;
- }
- - (objc_property_attribute_t *)list {
- // Regenerate list after mutations
- if (self.listDelta) {
- self.listDelta = NO;
- if (_list) {
- free(_list);
- _list = nil;
- }
- }
- // Super will generate the list if it isn't set
- return super.list;
- }
- - (NSString *)string {
- // Regenerate string after mutations
- if (self.stringDelta || !_string) {
- self.stringDelta = NO;
- _string = self.dictionary.propertyAttributesString;
- }
- return _string;
- }
- - (NSDictionary *)dictionary {
- // Regenerate dictionary after mutations
- if (self.dictDelta || !_dictionary) {
- // _stringa nd _dictionary depend on each other,
- // so we must generate ONE by hand using our properties.
- // We arbitrarily choose to generate the dictionary.
- NSMutableDictionary *attrs = [NSMutableDictionary new];
- if (self.typeEncoding)
- attrs[kFLEXPropertyAttributeKeyTypeEncoding] = self.typeEncoding;
- if (self.backingIvar)
- attrs[kFLEXPropertyAttributeKeyBackingIvarName] = self.backingIvar;
- if (self.oldTypeEncoding)
- attrs[kFLEXPropertyAttributeKeyOldStyleTypeEncoding] = self.oldTypeEncoding;
- if (self.customGetter)
- attrs[kFLEXPropertyAttributeKeyCustomGetter] = NSStringFromSelector(self.customGetter);
- if (self.customSetter)
- attrs[kFLEXPropertyAttributeKeyCustomSetter] = NSStringFromSelector(self.customSetter);
- if (self.isReadOnly) attrs[kFLEXPropertyAttributeKeyReadOnly] = @YES;
- if (self.isCopy) attrs[kFLEXPropertyAttributeKeyCopy] = @YES;
- if (self.isRetained) attrs[kFLEXPropertyAttributeKeyRetain] = @YES;
- if (self.isNonatomic) attrs[kFLEXPropertyAttributeKeyNonAtomic] = @YES;
- if (self.isDynamic) attrs[kFLEXPropertyAttributeKeyDynamic] = @YES;
- if (self.isWeak) attrs[kFLEXPropertyAttributeKeyWeak] = @YES;
- if (self.isGarbageCollectable) attrs[kFLEXPropertyAttributeKeyGarbageCollectable] = @YES;
- _dictionary = attrs.copy;
- }
- return _dictionary;
- }
- - (NSString *)fullDeclaration {
- if (self.declDelta || !_fullDeclaration) {
- _declDelta = NO;
- _fullDeclaration = [self buildFullDeclaration];
- }
- return _fullDeclaration;
- }
- - (NSString *)customGetterString {
- return _customGetter ? NSStringFromSelector(_customGetter) : nil;
- }
- - (NSString *)customSetterString {
- return _customSetter ? NSStringFromSelector(_customSetter) : nil;
- }
- @end
|