Last active
October 20, 2022 15:47
-
-
Save 0xstragner/ea86d5f457fb6d0f9ede3c459217441b to your computer and use it in GitHub Desktop.
Medium/UISheetPresentationController/2.m
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// SAPatternReference | |
// | |
@interface SAPatternReference : NSObject | |
@property (nonatomic, readonly, strong) NSString *name; | |
@property (nonatomic, readonly, assign) Class klass; | |
- (instancetype)init NS_UNAVAILABLE; | |
+ (instancetype)referenceWithNamed:(NSString *)name | |
klass:(Class)klass; | |
@end | |
@implementation SAPatternReference | |
- (instancetype)initWithNamed:(NSString *)name | |
klass:(Class)klass; | |
{ | |
self = [super init]; | |
if (self != nil) { | |
_name = [name copy]; | |
_klass = klass; | |
} | |
return self; | |
} | |
+ (instancetype)referenceWithNamed:(NSString *)name | |
klass:(Class)klass | |
{ | |
return [[SAPatternReference alloc] initWithNamed:name | |
klass:klass]; | |
} | |
@end | |
// | |
// SAClassRegistration | |
// | |
@interface SAClassRegistration : NSObject | |
- (instancetype)init NS_UNAVAILABLE; | |
- (instancetype)initWithClassNamed:(NSString *)className | |
superclassNamed:(NSString *)superclassName; | |
- (Class)registerClass; | |
- (void)registerInstancePropertyWithReference:(SAPatternReference *)patternReference | |
getterExecutionBlock:(id)getterExecutionBlock | |
setterExecutionBlock:(id)setterExecutionBlock; | |
- (void)registerInstanceMethodWithReference:(SAPatternReference *)patternReference | |
executionBlock:(id)executionBlock; | |
@end | |
@interface SAClassRegistration () | |
@property (nonatomic, readonly, assign) Class klass; | |
@property (nonatomic, readonly, assign) Class superklass; | |
@property (nonatomic, assign, getter=isKlassRegistered) BOOL klassRegistered; | |
@end | |
@implementation SAClassRegistration | |
- (instancetype)initWithClassNamed:(NSString *)className | |
superclassNamed:(NSString *)superclassName | |
{ | |
self = [super init]; | |
if (self != nil) { | |
Class superklass = NSClassFromString(superclassName); | |
if (superklass == NULL) { | |
[[NSException exceptionWithName:NSGenericException | |
reason:[NSString stringWithFormat:@"Class `%@` not found", className] | |
userInfo:nil] raise]; | |
} | |
_superklass = superklass; | |
_klass = objc_allocateClassPair(_superklass, [className UTF8String], 0); | |
_klassRegistered = NO; | |
} | |
return self; | |
} | |
- (Class)registerClass { | |
if (!self.isKlassRegistered) { | |
objc_registerClassPair(self.klass); | |
} | |
return self.klass; | |
} | |
#pragma mark - Methods & Properties Registration | |
- (void)registerInstancePropertyWithReference:(SAPatternReference *)patternReference | |
getterExecutionBlock:(id)getterExecutionBlock | |
setterExecutionBlock:(id)setterExecutionBlock | |
{ | |
[self registrationExceptionIfNeeded]; | |
Class patternClass = patternReference.klass; | |
unsigned attributeListCount; | |
objc_property_t patternProperty = class_getProperty(patternClass, [patternReference.name UTF8String]); | |
objc_property_attribute_t *attributeList = property_copyAttributeList(patternProperty, &attributeListCount); | |
class_addProperty(self.klass, [patternReference.name UTF8String], attributeList, attributeListCount); | |
free(attributeList); | |
NSString *getterMethodName = patternReference.name; | |
[self registerInstanceMethodWithReference:[SAPatternReference referenceWithNamed:getterMethodName klass:patternClass] | |
executionBlock:getterExecutionBlock]; | |
NSString *capitalizedName = [NSString stringWithFormat:@"%@%@", [[getterMethodName substringToIndex:1] uppercaseString], [getterMethodName substringFromIndex:1]]; | |
NSString *setterMethodName = [NSString stringWithFormat:@"set%@:", capitalizedName]; | |
[self registerInstanceMethodWithReference:[SAPatternReference referenceWithNamed:setterMethodName klass:patternClass] | |
executionBlock:setterExecutionBlock]; | |
} | |
- (void)registerInstanceMethodWithReference:(SAPatternReference *)patternReference | |
executionBlock:(id)executionBlock | |
{ | |
[self registrationExceptionIfNeeded]; | |
SEL patternSelector = NSSelectorFromString(patternReference.name); | |
const char *patternTypeEncoding = method_getTypeEncoding(class_getInstanceMethod(patternReference.klass, patternSelector)); | |
class_addMethod(self.klass, patternSelector, imp_implementationWithBlock(executionBlock), patternTypeEncoding); | |
} | |
#pragma mark - Private | |
- (void)registrationExceptionIfNeeded { | |
if (!self.isKlassRegistered) { | |
return; | |
} | |
[[NSException exceptionWithName:NSGenericException | |
reason:@"Class already registered and can not being modified." | |
userInfo:nil] raise]; | |
} | |
@end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment