mirror of
https://github.com/SoPat712/YTLitePlus.git
synced 2025-10-31 21:04:14 -04:00
377 lines
13 KiB
Objective-C
377 lines
13 KiB
Objective-C
//
|
|
// 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
|