123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218 |
- //
- // FLEXProtocol.m
- // FLEX
- //
- // Derived from MirrorKit.
- // Created by Tanner on 6/30/15.
- // Copyright (c) 2020 FLEX Team. All rights reserved.
- //
- #import "FLEXProtocol.h"
- #import "FLEXProperty.h"
- #import "FLEXRuntimeUtility.h"
- #import "NSArray+FLEX.h"
- #include <dlfcn.h>
- @implementation FLEXProtocol
- - (id)init {
- [NSException
- raise:NSInternalInconsistencyException
- format:@"Class instance should not be created with -init"
- ];
- return nil;
- }
- #pragma mark Initializers
- + (NSArray *)allProtocols {
- unsigned int prcount;
- Protocol *__unsafe_unretained*protocols = objc_copyProtocolList(&prcount);
-
- NSMutableArray *all = [NSMutableArray new];
- for(NSUInteger i = 0; i < prcount; i++)
- [all addObject:[self protocol:protocols[i]]];
-
- free(protocols);
- return all;
- }
- + (instancetype)protocol:(Protocol *)protocol {
- return [[self alloc] initWithProtocol:protocol];
- }
- - (id)initWithProtocol:(Protocol *)protocol {
- NSParameterAssert(protocol);
-
- self = [super init];
- if (self) {
- _objc_protocol = protocol;
- [self examine];
- }
-
- return self;
- }
- #pragma mark Other
- - (NSString *)description {
- return self.name;
- }
- - (NSString *)debugDescription {
- return [NSString stringWithFormat:@"<%@ name=%@, %lu properties, %lu required methods, %lu optional methods, %lu protocols>",
- NSStringFromClass(self.class), self.name, (unsigned long)self.properties.count,
- (unsigned long)self.requiredMethods.count, (unsigned long)self.optionalMethods.count, (unsigned long)self.protocols.count];
- }
- - (void)examine {
- _name = @(protocol_getName(self.objc_protocol));
-
- // imagePath
- Dl_info exeInfo;
- if (dladdr((__bridge const void *)(_objc_protocol), &exeInfo)) {
- _imagePath = exeInfo.dli_fname ? @(exeInfo.dli_fname) : nil;
- }
-
- // Conformances and methods //
-
- unsigned int pccount, mdrcount, mdocount;
- struct objc_method_description *objcrMethods, *objcoMethods;
- Protocol *protocol = _objc_protocol;
- Protocol * __unsafe_unretained *protocols = protocol_copyProtocolList(protocol, &pccount);
-
- // Protocols
- _protocols = [NSArray flex_forEachUpTo:pccount map:^id(NSUInteger i) {
- return [FLEXProtocol protocol:protocols[i]];
- }];
- free(protocols);
-
- // Required instance methods
- objcrMethods = protocol_copyMethodDescriptionList(protocol, YES, YES, &mdrcount);
- NSArray *rMethods = [NSArray flex_forEachUpTo:mdrcount map:^id(NSUInteger i) {
- return [FLEXMethodDescription description:objcrMethods[i] instance:YES];
- }];
- free(objcrMethods);
-
- // Required class methods
- objcrMethods = protocol_copyMethodDescriptionList(protocol, YES, NO, &mdrcount);
- _requiredMethods = [[NSArray flex_forEachUpTo:mdrcount map:^id(NSUInteger i) {
- return [FLEXMethodDescription description:objcrMethods[i] instance:NO];
- }] arrayByAddingObjectsFromArray:rMethods];
- free(objcrMethods);
-
- // Optional instance methods
- objcoMethods = protocol_copyMethodDescriptionList(protocol, NO, YES, &mdocount);
- NSArray *oMethods = [NSArray flex_forEachUpTo:mdocount map:^id(NSUInteger i) {
- return [FLEXMethodDescription description:objcoMethods[i] instance:YES];
- }];
- free(objcoMethods);
-
- // Optional class methods
- objcoMethods = protocol_copyMethodDescriptionList(protocol, NO, NO, &mdocount);
- _optionalMethods = [[NSArray flex_forEachUpTo:mdocount map:^id(NSUInteger i) {
- return [FLEXMethodDescription description:objcoMethods[i] instance:NO];
- }] arrayByAddingObjectsFromArray:oMethods];
- free(objcoMethods);
-
- // Properties is a hassle because they didn't fix the API until iOS 10 //
-
- if (@available(iOS 10.0, *)) {
- unsigned int prrcount, procount;
- Class instance = [NSObject class], meta = objc_getMetaClass("NSObject");
-
- // Required class and instance properties //
-
- // Instance first
- objc_property_t *rProps = protocol_copyPropertyList2(protocol, &prrcount, YES, YES);
- NSArray *rProperties = [NSArray flex_forEachUpTo:prrcount map:^id(NSUInteger i) {
- return [FLEXProperty property:rProps[i] onClass:instance];
- }];
- free(rProps);
-
- // Then class
- rProps = protocol_copyPropertyList2(protocol, &prrcount, NO, YES);
- _requiredProperties = [[NSArray flex_forEachUpTo:prrcount map:^id(NSUInteger i) {
- return [FLEXProperty property:rProps[i] onClass:instance];
- }] arrayByAddingObjectsFromArray:rProperties];
- free(rProps);
-
- // Optional class and instance properties //
-
- // Instance first
- objc_property_t *oProps = protocol_copyPropertyList2(protocol, &procount, YES, YES);
- NSArray *oProperties = [NSArray flex_forEachUpTo:prrcount map:^id(NSUInteger i) {
- return [FLEXProperty property:oProps[i] onClass:meta];
- }];
- free(oProps);
-
- // Then class
- oProps = protocol_copyPropertyList2(protocol, &procount, NO, YES);
- _optionalProperties = [[NSArray flex_forEachUpTo:procount map:^id(NSUInteger i) {
- return [FLEXProperty property:oProps[i] onClass:meta];
- }] arrayByAddingObjectsFromArray:oProperties];
- free(oProps);
-
- } else {
- unsigned int prcount;
- objc_property_t *objcproperties = protocol_copyPropertyList(protocol, &prcount);
- _properties = [NSArray flex_forEachUpTo:prcount map:^id(NSUInteger i) {
- return [FLEXProperty property:objcproperties[i]];
- }];
-
- free(objcproperties);
- }
- }
- - (BOOL)conformsTo:(Protocol *)protocol {
- return protocol_conformsToProtocol(self.objc_protocol, protocol);
- }
- @end
- #pragma mark FLEXMethodDescription
- @implementation FLEXMethodDescription
- - (id)init {
- [NSException
- raise:NSInternalInconsistencyException
- format:@"Class instance should not be created with -init"
- ];
- return nil;
- }
- + (instancetype)description:(struct objc_method_description)description {
- return [[self alloc] initWithDescription:description instance:nil];
- }
- + (instancetype)description:(struct objc_method_description)description instance:(BOOL)isInstance {
- return [[self alloc] initWithDescription:description instance:@(isInstance)];
- }
- - (id)initWithDescription:(struct objc_method_description)md instance:(NSNumber *)instance {
- NSParameterAssert(md.name != NULL);
-
- self = [super init];
- if (self) {
- _objc_description = md;
- _selector = md.name;
- _typeEncoding = @(md.types);
- _returnType = (FLEXTypeEncoding)[self.typeEncoding characterAtIndex:0];
- _instance = instance;
- }
-
- return self;
- }
- - (NSString *)description {
- return NSStringFromSelector(self.selector);
- }
- - (NSString *)debugDescription {
- return [NSString stringWithFormat:@"<%@ name=%@, type=%@>",
- NSStringFromClass(self.class), NSStringFromSelector(self.selector), self.typeEncoding];
- }
- @end
|