Переглянути джерело

Runtime wrapper upgrades

- Make sure every object has an `imageName` property
- Expose more fine-grained metadata through FLEXProtocol
- Migrate flex_all* methods to top-level functions that the methods call into
Tanner Bennett 6 роки тому
батько
коміт
142f037497

+ 11 - 0
Classes/Utility/Categories/NSObject+Reflection.h

@@ -25,6 +25,17 @@ NSArray<Class> *FLEXGetAllSubclasses(_Nullable Class cls, BOOL includeSelf);
 NSArray<Class> *FLEXGetClassHierarchy(_Nullable Class cls, BOOL includeSelf);
 NSArray<FLEXProtocol *> *FLEXGetConformedProtocols(_Nullable Class cls);
 
+NSArray<FLEXIvar *> *FLEXGetAllIvars(_Nullable Class cls);
+/// @param cls a class object to get instance properties,
+/// or a metaclass object to get class properties
+NSArray<FLEXProperty *> *FLEXGetAllProperties(_Nullable Class cls);
+/// @param cls a class object to get instance methods,
+/// or a metaclass object to get class methods
+/// @param instance used to mark methods as instance methods or not.
+/// Not used to determine whether to get instance or class methods. 
+NSArray<FLEXMethod *> *FLEXGetAllMethods(_Nullable Class cls, BOOL instance);
+
+
 
 #pragma mark Reflection
 @interface NSObject (Reflection)

+ 49 - 57
Classes/Utility/Categories/NSObject+Reflection.m

@@ -101,6 +101,45 @@ NSArray<FLEXProtocol *> *FLEXGetConformedProtocols(Class cls) {
     }];
 }
 
+NSArray<FLEXIvar *> *FLEXGetAllIvars(_Nullable Class cls) {
+    if (!cls) return nil;
+    
+    unsigned int ivcount;
+    Ivar *objcivars = class_copyIvarList(cls, &ivcount);
+    NSArray *ivars = [NSArray flex_forEachUpTo:ivcount map:^id(NSUInteger i) {
+        return [FLEXIvar ivar:objcivars[i]];
+    }];
+
+    free(objcivars);
+    return ivars;
+}
+
+NSArray<FLEXProperty *> *FLEXGetAllProperties(_Nullable Class cls) {
+    if (!cls) return nil;
+    
+    unsigned int pcount;
+    objc_property_t *objcproperties = class_copyPropertyList(cls, &pcount);
+    NSArray *properties = [NSArray flex_forEachUpTo:pcount map:^id(NSUInteger i) {
+        return [FLEXProperty property:objcproperties[i] onClass:cls];
+    }];
+
+    free(objcproperties);
+    return properties;
+}
+
+NSArray<FLEXMethod *> *FLEXGetAllMethods(_Nullable Class cls, BOOL instance) {
+    if (!cls) return nil;
+
+    unsigned int mcount;
+    Method *objcmethods = class_copyMethodList(cls, &mcount);
+    NSArray *methods = [NSArray flex_forEachUpTo:mcount map:^id(NSUInteger i) {
+        return [FLEXMethod method:objcmethods[i] isInstanceMethod:instance];
+    }];
+    
+    free(objcmethods);
+    return methods;
+}
+
 
 #pragma mark NSProxy
 
@@ -135,6 +174,11 @@ NSArray<FLEXProtocol *> *FLEXGetConformedProtocols(Class cls) {
         FLEXClassBuilder *swiftObjectMeta = [FLEXClassBuilder builderForClass:SwiftObject_meta];
         [swiftObject addMethods:instanceMethods];
         [swiftObjectMeta addMethods:classMethods];
+        
+        // So we can put Swift objects into dictionaries...
+        [swiftObjectMeta addMethods:@[
+            [NSObject flex_classMethodNamed:@"copyWithZone:"]]
+        ];
     }
 }
 
@@ -198,35 +242,11 @@ NSArray<FLEXProtocol *> *FLEXGetConformedProtocols(Class cls) {
 }
 
 + (NSArray<FLEXMethod *> *)flex_allInstanceMethods {
-    unsigned int mcount;
-    Method *objcmethods = class_copyMethodList([self class], &mcount);
-
-    NSMutableArray *methods = [NSMutableArray new];
-    for (int i = 0; i < mcount; i++) {
-        FLEXMethod *m = [FLEXMethod method:objcmethods[i] isInstanceMethod:YES];
-        if (m) {
-            [methods addObject:m];
-        }
-    }
-
-    free(objcmethods);
-    return methods;
+    return FLEXGetAllMethods(self, YES);
 }
 
 + (NSArray<FLEXMethod *> *)flex_allClassMethods {
-    unsigned int mcount;
-    Method *objcmethods = class_copyMethodList(self.flex_metaclass, &mcount);
-
-    NSMutableArray *methods = [NSMutableArray new];
-    for (int i = 0; i < mcount; i++) {
-        FLEXMethod *m = [FLEXMethod method:objcmethods[i] isInstanceMethod:NO];
-        if (m) {
-            [methods addObject:m];
-        }
-    }
-
-    free(objcmethods);
-    return methods;
+    return FLEXGetAllMethods(self.flex_metaclass, NO);
 }
 
 + (FLEXMethod *)flex_methodNamed:(NSString *)name {
@@ -292,16 +312,7 @@ NSArray<FLEXProtocol *> *FLEXGetConformedProtocols(Class cls) {
 @implementation NSObject (Ivars)
 
 + (NSArray<FLEXIvar *> *)flex_allIvars {
-    unsigned int ivcount;
-    Ivar *objcivars = class_copyIvarList([self class], &ivcount);
-    
-    NSMutableArray *ivars = [NSMutableArray new];
-    for (int i = 0; i < ivcount; i++) {
-        [ivars addObject:[FLEXIvar ivar:objcivars[i]]];
-    }
-
-    free(objcivars);
-    return ivars;
+    return FLEXGetAllIvars(self);
 }
 
 + (FLEXIvar *)flex_ivarNamed:(NSString *)name {
@@ -379,30 +390,11 @@ NSArray<FLEXProtocol *> *FLEXGetConformedProtocols(Class cls) {
 }
 
 + (NSArray<FLEXProperty *> *)flex_allInstanceProperties {
-    unsigned int pcount;
-    objc_property_t *objcproperties = class_copyPropertyList(self, &pcount);
-    
-    NSMutableArray *properties = [NSMutableArray new];
-    for (int i = 0; i < pcount; i++) {
-        [properties addObject:[FLEXProperty property:objcproperties[i] onClass:self]];
-    }
-
-    free(objcproperties);
-    return properties;
+    return FLEXGetAllProperties(self);
 }
 
 + (NSArray<FLEXProperty *> *)flex_allClassProperties {
-    Class metaclass = self.flex_metaclass;
-    unsigned int pcount;
-    objc_property_t *objcproperties = class_copyPropertyList(metaclass, &pcount);
-
-    NSMutableArray *properties = [NSMutableArray new];
-    for (int i = 0; i < pcount; i++) {
-        [properties addObject:[FLEXProperty property:objcproperties[i] onClass:metaclass]];
-    }
-
-    free(objcproperties);
-    return properties;
+    return FLEXGetAllProperties(self.flex_metaclass);
 }
 
 + (FLEXProperty *)flex_propertyNamed:(NSString *)name {

+ 3 - 0
Classes/Utility/Runtime/Objc/Reflection/FLEXIvar.h

@@ -29,6 +29,9 @@
 @property (nonatomic, readonly) NSUInteger       size;
 /// Describes the type encoding, size, offset, and objc_ivar
 @property (nonatomic, readonly) NSString        *details;
+/// The full path of the image that contains this ivar definition,
+/// or \c nil if this ivar was probably defined at runtime.
+@property (nonatomic, readonly) NSString        *imagePath;
 
 /// For internal use
 @property (nonatomic) id tag;

+ 6 - 0
Classes/Utility/Runtime/Objc/Reflection/FLEXIvar.m

@@ -11,6 +11,7 @@
 #import "FLEXRuntimeUtility.h"
 #import "FLEXRuntimeSafety.h"
 #import "FLEXTypeEncodingParser.h"
+#include <dlfcn.h>
 
 @interface FLEXIvar () {
     NSString *_flex_description;
@@ -82,6 +83,11 @@
         typeForDetails = @"no type info";
         sizeForDetails = @"unknown size";
     }
+    
+    Dl_info exeInfo;
+    if (dladdr(_objc_ivar, &exeInfo)) {
+        _imagePath = exeInfo.dli_fname ? @(exeInfo.dli_fname) : nil;
+    }
 
     _details = [NSString stringWithFormat:
         @"%@, offset %@  —  %@",

+ 3 - 0
Classes/Utility/Runtime/Objc/Reflection/FLEXMethod.h

@@ -59,6 +59,9 @@ NS_ASSUME_NONNULL_BEGIN
 @property (nonatomic, readonly) FLEXTypeEncoding  *returnType;
 /// The return size of the method.
 @property (nonatomic, readonly) NSUInteger        returnSize;
+/// The full path of the image that contains this method definition,
+/// or \c nil if this ivar was probably defined at runtime.
+@property (nonatomic, readonly) NSString          *imagePath;
 
 /// Like @code - (void)foo:(int)bar @endcode
 @property (nonatomic, readonly) NSString *description;

+ 7 - 1
Classes/Utility/Runtime/Objc/Reflection/FLEXMethod.m

@@ -11,6 +11,7 @@
 #import "FLEXMirror.h"
 #import "FLEXTypeEncodingParser.h"
 #import "FLEXRuntimeUtility.h"
+#include <dlfcn.h>
 
 @implementation FLEXMethod
 @dynamic implementation;
@@ -153,8 +154,13 @@
     _selector          = method_getName(_objc_method);
     _numberOfArguments = method_getNumberOfArguments(_objc_method);
     _name              = NSStringFromSelector(_selector);
-    _returnType        = (FLEXTypeEncoding *)_signature.methodReturnType;
+    _returnType        = (FLEXTypeEncoding *)_signature.methodReturnType ?: "";
     _returnSize        = _signature.methodReturnLength;
+    
+    Dl_info exeInfo;
+    if (dladdr(_objc_method, &exeInfo)) {
+        _imagePath = exeInfo.dli_fname ? @(exeInfo.dli_fname) : nil;
+    }
 }
 
 #pragma mark Public

+ 5 - 1
Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.h

@@ -59,8 +59,12 @@
 @property (nonatomic, readonly) BOOL multiple;
 /// @return The bundle of the image that contains this property definition,
 /// or \c nil if this property was not created with \c property:onClass or
-/// if this property is probably defined in the objc runtime.
+/// if this property was probably defined at runtime.
 @property (nonatomic, readonly) NSString *imageName;
+/// The full path of the image that contains this property definition,
+/// or \c nil if this property was not created with \c property:onClass or
+/// if this property was probably defined at runtime.
+@property (nonatomic, readonly) NSString *imagePath;
 
 /// For internal use
 @property (nonatomic) id tag;

+ 15 - 4
Classes/Utility/Runtime/Objc/Reflection/FLEXProperty.m

@@ -24,6 +24,7 @@
 @implementation FLEXProperty
 @synthesize multiple = _multiple;
 @synthesize imageName = _imageName;
+@synthesize imagePath = _imagePath;
 
 #pragma mark Initializers
 
@@ -88,7 +89,9 @@
 #pragma mark Private
 
 - (void)examine {
-    _type = (FLEXTypeEncoding)[self.attributes.typeEncoding characterAtIndex:0];
+    if (self.attributes.typeEncoding.length) {
+        _type = (FLEXTypeEncoding)[self.attributes.typeEncoding characterAtIndex:0];
+    }
 
     // Return the given selector if the class responds to it
     Class cls = _cls;
@@ -153,13 +156,16 @@
 }
 
 - (void)computeSymbolInfo:(BOOL)forceBundle {
+    Dl_info exeInfo;
+    if (dladdr(_objc_property, &exeInfo)) {
+        _imagePath = exeInfo.dli_fname ? @(exeInfo.dli_fname) : nil;
+    }
+    
     if ((!_multiple || !_uniqueCheckFlag) && _cls) {
         _multiple = _objc_property != class_getProperty(_cls, self.name.UTF8String);
 
         if (_multiple || forceBundle) {
-            Dl_info exeInfo;
-            dladdr(_objc_property, &exeInfo);
-            NSString *path = @(exeInfo.dli_fname).stringByDeletingLastPathComponent;
+            NSString *path = _imagePath.stringByDeletingLastPathComponent;
             _imageName = [NSBundle bundleWithPath:path].executablePath.lastPathComponent;
         }
     }
@@ -170,6 +176,11 @@
     return _multiple;
 }
 
+- (NSString *)imagePath {
+    [self computeSymbolInfo:YES];
+    return _imagePath;
+}
+
 - (NSString *)imageName {
     [self computeSymbolInfo:YES];
     return _imageName;

+ 4 - 0
Classes/Utility/Runtime/Objc/Reflection/FLEXPropertyAttributes.h

@@ -60,6 +60,10 @@ NS_ASSUME_NONNULL_BEGIN
 @property (nonatomic, readonly, nullable) SEL customGetter;
 /// The property's custom setter, if any.
 @property (nonatomic, readonly, nullable) SEL customSetter;
+/// The property's custom getter as a string, if any.
+@property (nonatomic, readonly, nullable) NSString *customGetterString;
+/// The property's custom setter as a string, if any.
+@property (nonatomic, readonly, nullable) NSString *customSetterString;
 
 @property (nonatomic, readonly) BOOL isReadOnly;
 @property (nonatomic, readonly) BOOL isCopy;

+ 12 - 2
Classes/Utility/Runtime/Objc/Reflection/FLEXPropertyAttributes.m

@@ -58,8 +58,10 @@
         _typeEncoding         = attributes[kFLEXPropertyAttributeKeyTypeEncoding];
         _backingIvar          = attributes[kFLEXPropertyAttributeKeyBackingIvarName];
         _oldTypeEncoding      = attributes[kFLEXPropertyAttributeKeyOldStyleTypeEncoding];
-        _customGetter         = NSSelectorFromString(attributes[kFLEXPropertyAttributeKeyCustomGetter]);
-        _customSetter         = NSSelectorFromString(attributes[kFLEXPropertyAttributeKeyCustomSetter]);
+        _customGetterString   = attributes[kFLEXPropertyAttributeKeyCustomGetter];
+        _customSetterString   = attributes[kFLEXPropertyAttributeKeyCustomSetter];
+        _customGetter         = NSSelectorFromString(_customGetterString);
+        _customSetter         = NSSelectorFromString(_customSetterString);
         _isReadOnly           = attributes[kFLEXPropertyAttributeKeyReadOnly] != nil;
         _isCopy               = attributes[kFLEXPropertyAttributeKeyCopy] != nil;
         _isRetained           = attributes[kFLEXPropertyAttributeKeyRetain] != nil;
@@ -363,4 +365,12 @@ PropertyWithDeltaFlag(BOOL, isGarbageCollectable, IsGarbageCollectable);
     return _fullDeclaration;
 }
 
+- (NSString *)customGetterString {
+    return _customGetter ? NSStringFromSelector(_customGetter) : nil;
+}
+
+- (NSString *)customSetterString {
+    return _customSetter ? NSStringFromSelector(_customSetter) : nil;
+}
+
 @end

+ 15 - 3
Classes/Utility/Runtime/Objc/Reflection/FLEXProtocol.h

@@ -22,14 +22,23 @@
 
 /// The name of the protocol.
 @property (nonatomic, readonly) NSString *name;
-/// The properties in the protocol, if any.
-@property (nonatomic, readonly) NSArray<FLEXProperty *>  *properties;
 /// The required methods of the protocol, if any. This includes property getters and setters.
 @property (nonatomic, readonly) NSArray<FLEXMethodDescription *>  *requiredMethods;
 /// The optional methods of the protocol, if any. This includes property getters and setters.
 @property (nonatomic, readonly) NSArray<FLEXMethodDescription *>  *optionalMethods;
 /// All protocols that this protocol conforms to, if any.
 @property (nonatomic, readonly) NSArray<FLEXProtocol *>  *protocols;
+/// The full path of the image that contains this protocol definition,
+/// or \c nil if this protocol was probably defined at runtime.
+@property (nonatomic, readonly) NSString *imagePath;
+
+/// The properties in the protocol, if any. \c nil on iOS 10+ 
+@property (nonatomic, readonly) NSArray<FLEXProperty *>  *properties API_DEPRECATED("Use the more specific accessors below", ios(2.0, 10.0));
+
+/// The required properties in the protocol, if any.
+@property (nonatomic, readonly) NSArray<FLEXProperty *>  *requiredProperties API_AVAILABLE(ios(10.0));
+/// The optional properties in the protocol, if any.
+@property (nonatomic, readonly) NSArray<FLEXProperty *>  *optionalProperties API_AVAILABLE(ios(10.0));
 
 /// For internal use
 @property (nonatomic) id tag;
@@ -44,7 +53,8 @@
 #pragma mark Method descriptions
 @interface FLEXMethodDescription : NSObject
 
-+ (instancetype)description:(struct objc_method_description)methodDescription;
++ (instancetype)description:(struct objc_method_description)description;
++ (instancetype)description:(struct objc_method_description)description instance:(BOOL)isInstance;
 
 /// The underlying method description data structure.
 @property (nonatomic, readonly) struct objc_method_description objc_description;
@@ -54,4 +64,6 @@
 @property (nonatomic, readonly) NSString *typeEncoding;
 /// The method's return type.
 @property (nonatomic, readonly) FLEXTypeEncoding returnType;
+/// \c @YES if this is an instance method, \c @NO if it is a class method, or \c nil if unspecified
+@property (nonatomic, readonly) NSNumber *instance;
 @end

+ 105 - 35
Classes/Utility/Runtime/Objc/Reflection/FLEXProtocol.m

@@ -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;