|
|
@@ -10,7 +10,8 @@
|
|
|
#import "FLEXProtocol.h"
|
|
|
#import "FLEXProperty.h"
|
|
|
#import "FLEXRuntimeUtility.h"
|
|
|
-
|
|
|
+#import "NSArray+Functional.h"
|
|
|
+#include <dlfcn.h>
|
|
|
|
|
|
@implementation FLEXProtocol
|
|
|
|
|
|
@@ -66,37 +67,101 @@
|
|
|
|
|
|
- (void)examine {
|
|
|
_name = @(protocol_getName(self.objc_protocol));
|
|
|
- unsigned int prcount, pccount, mdrcount, mdocount;
|
|
|
-
|
|
|
- objc_property_t *objcproperties = protocol_copyPropertyList(self.objc_protocol, &prcount);
|
|
|
- Protocol * __unsafe_unretained *objcprotocols = protocol_copyProtocolList(self.objc_protocol, &pccount);
|
|
|
- struct objc_method_description *objcrmethods = protocol_copyMethodDescriptionList(self.objc_protocol, YES, YES, &mdrcount);
|
|
|
- struct objc_method_description *objcomethods = protocol_copyMethodDescriptionList(self.objc_protocol, NO, YES, &mdocount);
|
|
|
-
|
|
|
- NSMutableArray *properties = [NSMutableArray new];
|
|
|
- for (int i = 0; i < prcount; i++)
|
|
|
- [properties addObject:[FLEXProperty property:objcproperties[i]]];
|
|
|
- _properties = properties;
|
|
|
-
|
|
|
- NSMutableArray *protocols = [NSMutableArray new];
|
|
|
- for (int i = 0; i < pccount; i++)
|
|
|
- [protocols addObject:[FLEXProtocol protocol:objcprotocols[i]]];
|
|
|
- _protocols = protocols;
|
|
|
-
|
|
|
- NSMutableArray *requiredMethods = [NSMutableArray new];
|
|
|
- for (int i = 0; i < mdrcount; i++)
|
|
|
- [requiredMethods addObject:[FLEXMethodDescription description:objcrmethods[i]]];
|
|
|
- _requiredMethods = requiredMethods;
|
|
|
-
|
|
|
- NSMutableArray *optionalMethods = [NSMutableArray new];
|
|
|
- for (int i = 0; i < mdocount; i++)
|
|
|
- [optionalMethods addObject:[FLEXMethodDescription description:objcomethods[i]]];
|
|
|
- _optionalMethods = optionalMethods;
|
|
|
-
|
|
|
- free(objcproperties);
|
|
|
- free(objcprotocols);
|
|
|
- free(objcrmethods);
|
|
|
- free(objcomethods);
|
|
|
+
|
|
|
+ // 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]];
|
|
|
+ }];
|
|
|
+ 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]];
|
|
|
+ }] 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]];
|
|
|
+ }];
|
|
|
+ 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]];
|
|
|
+ }] 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 {
|
|
|
@@ -117,11 +182,15 @@
|
|
|
return nil;
|
|
|
}
|
|
|
|
|
|
-+ (instancetype)description:(struct objc_method_description)methodDescription {
|
|
|
- return [[self alloc] initWithDescription:methodDescription];
|
|
|
++ (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 {
|
|
|
+- (id)initWithDescription:(struct objc_method_description)md instance:(NSNumber *)instance {
|
|
|
NSParameterAssert(md.name != NULL);
|
|
|
|
|
|
self = [super init];
|
|
|
@@ -130,6 +199,7 @@
|
|
|
_selector = md.name;
|
|
|
_typeEncoding = @(md.types);
|
|
|
_returnType = (FLEXTypeEncoding)[self.typeEncoding characterAtIndex:0];
|
|
|
+ _instance = instance;
|
|
|
}
|
|
|
|
|
|
return self;
|