NSObject+FLEX_Reflection.h 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  1. //
  2. // NSObject+FLEX_Reflection.h
  3. // FLEX
  4. //
  5. // Derived from MirrorKit.
  6. // Created by Tanner on 6/30/15.
  7. // Copyright (c) 2020 FLEX Team. All rights reserved.
  8. //
  9. #import <Foundation/Foundation.h>
  10. #import <UIKit/UIKit.h>
  11. #import <objc/runtime.h>
  12. @class FLEXMirror, FLEXMethod, FLEXIvar, FLEXProperty, FLEXMethodBase, FLEXPropertyAttributes, FLEXProtocol;
  13. NS_ASSUME_NONNULL_BEGIN
  14. @interface NSObject (tvOS)
  15. - (UIViewController *)topViewController;
  16. - (BOOL)darkMode;
  17. @end
  18. /// Returns the type encoding string given the encoding for the return type and parameters, if any.
  19. /// @discussion Example usage for a \c void returning method which takes
  20. /// an \c int: @code FLEXTypeEncoding(@encode(void), @encode(int));
  21. /// @param returnType The encoded return type. \c void for exmaple would be \c @encode(void).
  22. /// @param count The number of parameters in this type encoding string.
  23. /// @return The type encoding string, or \c nil if \e returnType is \c NULL.
  24. NSString * FLEXTypeEncodingString(const char *returnType, NSUInteger count, ...);
  25. NSArray<Class> *FLEXGetAllSubclasses(_Nullable Class cls, BOOL includeSelf);
  26. NSArray<Class> *FLEXGetClassHierarchy(_Nullable Class cls, BOOL includeSelf);
  27. NSArray<FLEXProtocol *> *FLEXGetConformedProtocols(_Nullable Class cls);
  28. NSArray<FLEXIvar *> *FLEXGetAllIvars(_Nullable Class cls);
  29. /// @param cls a class object to get instance properties,
  30. /// or a metaclass object to get class properties
  31. NSArray<FLEXProperty *> *FLEXGetAllProperties(_Nullable Class cls);
  32. /// @param cls a class object to get instance methods,
  33. /// or a metaclass object to get class methods
  34. /// @param instance used to mark methods as instance methods or not.
  35. /// Not used to determine whether to get instance or class methods.
  36. NSArray<FLEXMethod *> *FLEXGetAllMethods(_Nullable Class cls, BOOL instance);
  37. /// @param cls a class object to get all instance and class methods.
  38. NSArray<FLEXMethod *> *FLEXGetAllInstanceAndClassMethods(_Nullable Class cls);
  39. #pragma mark Reflection
  40. @interface NSObject (Reflection)
  41. @property (nonatomic, readonly ) FLEXMirror *flex_reflection;
  42. @property (nonatomic, readonly, class) FLEXMirror *flex_reflection;
  43. /// Calls into /c FLEXGetAllSubclasses
  44. /// @return Every subclass of the receiving class, including the receiver itself.
  45. @property (nonatomic, readonly, class) NSArray<Class> *flex_allSubclasses;
  46. /// @return The \c Class object for the metaclass of the recieving class, or \c Nil if the class is Nil or not registered.
  47. @property (nonatomic, readonly, class) Class flex_metaclass;
  48. /// @return The size in bytes of instances of the recieving class, or \c 0 if \e cls is \c Nil.
  49. @property (nonatomic, readonly, class) size_t flex_instanceSize;
  50. /// Changes the class of an object instance.
  51. /// @return The previous value of the objects \c class, or \c Nil if the object is \c nil.
  52. - (Class)flex_setClass:(Class)cls;
  53. /// Sets the recieving class's superclass. "You should not use this method" — Apple.
  54. /// @return The old superclass.
  55. + (Class)flex_setSuperclass:(Class)superclass;
  56. /// Calls into \c FLEXGetClassHierarchy()
  57. /// @return a list of classes going up the class hierarchy,
  58. /// starting with the receiver and ending with the root class.
  59. @property (nonatomic, readonly, class) NSArray<Class> *flex_classHierarchy;
  60. /// Calls into \c FLEXGetConformedProtocols
  61. /// @return a list of protocols this class itself conforms to.
  62. @property (nonatomic, readonly, class) NSArray<FLEXProtocol *> *flex_protocols;
  63. @end
  64. #pragma mark Methods
  65. @interface NSObject (Methods)
  66. /// All instance and class methods specific to the recieving class.
  67. /// @discussion This method will only retrieve methods specific to the recieving class.
  68. /// To retrieve instance variables on a parent class, simply call this on \c [self superclass].
  69. /// @return An array of \c FLEXMethod objects.
  70. @property (nonatomic, readonly, class) NSArray<FLEXMethod *> *flex_allMethods;
  71. /// All instance methods specific to the recieving class.
  72. /// @discussion This method will only retrieve methods specific to the recieving class.
  73. /// To retrieve instance variables on a parent class, simply call this on \c [self superclass].
  74. /// @return An array of \c FLEXMethod objects.
  75. @property (nonatomic, readonly, class) NSArray<FLEXMethod *> *flex_allInstanceMethods;
  76. /// All class methods specific to the recieving class.
  77. /// @discussion This method will only retrieve methods specific to the recieving class.
  78. /// To retrieve instance variables on a parent class, simply call this on \c [self superclass].
  79. /// @return An array of \c FLEXMethod objects.
  80. @property (nonatomic, readonly, class) NSArray<FLEXMethod *> *flex_allClassMethods;
  81. /// Retrieves the class's instance method with the given name.
  82. /// @return An initialized \c FLEXMethod object, or \c nil if the method wasn't found.
  83. + (FLEXMethod *)flex_methodNamed:(NSString *)name;
  84. /// Retrieves the class's class method with the given name.
  85. /// @return An initialized \c FLEXMethod object, or \c nil if the method wasn't found.
  86. + (FLEXMethod *)flex_classMethodNamed:(NSString *)name;
  87. /// Adds a new method to the recieving class with a given name and implementation.
  88. /// @discussion This method will add an override of a superclass's implementation,
  89. /// but will not replace an existing implementation in the class.
  90. /// To change an existing implementation, use \c replaceImplementationOfMethod:with:.
  91. ///
  92. /// Type encodings start with the return type and end with the parameter types in order.
  93. /// The type encoding for \c NSArray's \c count property getter looks like this:
  94. /// @code [NSString stringWithFormat:@"%s%s%s%s", @encode(void), @encode(id), @encode(SEL), @encode(NSUInteger)] @endcode
  95. /// Using the \c FLEXTypeEncoding function for the same method looks like this:
  96. /// @code FLEXTypeEncodingString(@encode(void), 1, @encode(NSUInteger)) @endcode
  97. /// @param typeEncoding The type encoding string. Consider using the \c FLEXTypeEncodingString() function.
  98. /// @param instanceMethod NO to add the method to the class itself or YES to add it as an instance method.
  99. /// @return YES if the method was added successfully, \c NO otherwise
  100. /// (for example, the class already contains a method implementation with that name).
  101. + (BOOL)addMethod:(SEL)selector
  102. typeEncoding:(NSString *)typeEncoding
  103. implementation:(IMP)implementaiton
  104. toInstances:(BOOL)instanceMethod;
  105. /// Replaces the implementation of a method in the recieving class.
  106. /// @param instanceMethod YES to replace the instance method, NO to replace the class method.
  107. /// @note This function behaves in two different ways:
  108. ///
  109. /// - If the method does not yet exist in the recieving class, it is added as if
  110. /// \c addMethod:typeEncoding:implementation were called.
  111. ///
  112. /// - If the method does exist, its \c IMP is replaced.
  113. /// @return The previous \c IMP of \e method.
  114. + (IMP)replaceImplementationOfMethod:(FLEXMethodBase *)method with:(IMP)implementation useInstance:(BOOL)instanceMethod;
  115. /// Swaps the implementations of the given methods.
  116. /// @discussion If one or neither of the given methods exist in the recieving class,
  117. /// they are added to the class with their implementations swapped as if each method did exist.
  118. /// This method will not fail if each \c FLEXSimpleMethod contains a valid selector.
  119. /// @param instanceMethod YES to swizzle the instance method, NO to swizzle the class method.
  120. + (void)swizzle:(FLEXMethodBase *)original with:(FLEXMethodBase *)other onInstance:(BOOL)instanceMethod;
  121. /// Swaps the implementations of the given methods.
  122. /// @param instanceMethod YES to swizzle the instance method, NO to swizzle the class method.
  123. /// @return \c YES if successful, and \c NO if selectors could not be retrieved from the given strings.
  124. + (BOOL)swizzleByName:(NSString *)original with:(NSString *)other onInstance:(BOOL)instanceMethod;
  125. /// Swaps the implementations of methods corresponding to the given selectors.
  126. + (void)swizzleBySelector:(SEL)original with:(SEL)other onInstance:(BOOL)instanceMethod;
  127. @end
  128. #pragma mark Properties
  129. @interface NSObject (Ivars)
  130. /// All of the instance variables specific to the recieving class.
  131. /// @discussion This method will only retrieve instance varibles specific to the recieving class.
  132. /// To retrieve instance variables on a parent class, simply call \c [[self superclass] allIvars].
  133. /// @return An array of \c FLEXIvar objects.
  134. @property (nonatomic, readonly, class) NSArray<FLEXIvar *> *flex_allIvars;
  135. /// Retrieves an instance variable with the corresponding name.
  136. /// @return An initialized \c FLEXIvar object, or \c nil if the Ivar wasn't found.
  137. + (FLEXIvar *)flex_ivarNamed:(NSString *)name;
  138. /// @return The address of the given ivar in the recieving object in memory,
  139. /// or \c NULL if it could not be found.
  140. - (void *)flex_getIvarAddress:(FLEXIvar *)ivar;
  141. /// @return The address of the given ivar in the recieving object in memory,
  142. /// or \c NULL if it could not be found.
  143. - (void *)flex_getIvarAddressByName:(NSString *)name;
  144. /// @discussion This method faster than creating an \c FLEXIvar and calling
  145. /// \c -getIvarAddress: if you already have an \c Ivar on hand
  146. /// @return The address of the given ivar in the recieving object in memory,
  147. /// or \c NULL if it could not be found\.
  148. - (void *)flex_getObjcIvarAddress:(Ivar)ivar;
  149. /// Sets the value of the given instance variable on the recieving object.
  150. /// @discussion Use only when the target instance variable is an object.
  151. - (void)flex_setIvar:(FLEXIvar *)ivar object:(id)value;
  152. /// Sets the value of the given instance variable on the recieving object.
  153. /// @discussion Use only when the target instance variable is an object.
  154. /// @return \c YES if successful, or \c NO if the instance variable could not be found.
  155. - (BOOL)flex_setIvarByName:(NSString *)name object:(id)value;
  156. /// @discussion Use only when the target instance variable is an object.
  157. /// This method is faster than creating an \c FLEXIvar and calling
  158. /// \c -setIvar: if you already have an \c Ivar on hand.
  159. - (void)flex_setObjcIvar:(Ivar)ivar object:(id)value;
  160. /// Sets the value of the given instance variable on the recieving object to the
  161. /// \e size number of bytes of data at \e value.
  162. /// @discussion Use one of the other methods if you can help it.
  163. - (void)flex_setIvar:(FLEXIvar *)ivar value:(void *)value size:(size_t)size;
  164. /// Sets the value of the given instance variable on the recieving object to the
  165. /// \e size number of bytes of data at \e value.
  166. /// @discussion Use one of the other methods if you can help it
  167. /// @return \c YES if successful, or \c NO if the instance variable could not be found.
  168. - (BOOL)flex_setIvarByName:(NSString *)name value:(void *)value size:(size_t)size;
  169. /// Sets the value of the given instance variable on the recieving object to the
  170. /// \e size number of bytes of data at \e value.
  171. /// @discussion This is faster than creating an \c FLEXIvar and calling
  172. /// \c -setIvar:value:size if you already have an \c Ivar on hand.
  173. - (void)flex_setObjcIvar:(Ivar)ivar value:(void *)value size:(size_t)size;
  174. @end
  175. #pragma mark Properties
  176. @interface NSObject (Properties)
  177. /// All instance and class properties specific to the recieving class.
  178. /// @discussion This method will only retrieve properties specific to the recieving class.
  179. /// To retrieve instance variables on a parent class, simply call this on \c [self superclass].
  180. /// @return An array of \c FLEXProperty objects.
  181. @property (nonatomic, readonly, class) NSArray<FLEXProperty *> *flex_allProperties;
  182. /// All instance properties specific to the recieving class.
  183. /// @discussion This method will only retrieve properties specific to the recieving class.
  184. /// To retrieve instance variables on a parent class, simply call this on \c [self superclass].
  185. /// @return An array of \c FLEXProperty objects.
  186. @property (nonatomic, readonly, class) NSArray<FLEXProperty *> *flex_allInstanceProperties;
  187. /// All class properties specific to the recieving class.
  188. /// @discussion This method will only retrieve properties specific to the recieving class.
  189. /// To retrieve instance variables on a parent class, simply call this on \c [self superclass].
  190. /// @return An array of \c FLEXProperty objects.
  191. @property (nonatomic, readonly, class) NSArray<FLEXProperty *> *flex_allClassProperties;
  192. /// Retrieves the class's property with the given name.
  193. /// @return An initialized \c FLEXProperty object, or \c nil if the property wasn't found.
  194. + (FLEXProperty *)flex_propertyNamed:(NSString *)name;
  195. /// @return An initialized \c FLEXProperty object, or \c nil if the property wasn't found.
  196. + (FLEXProperty *)flex_classPropertyNamed:(NSString *)name;
  197. /// Replaces the given property on the recieving class.
  198. + (void)flex_replaceProperty:(FLEXProperty *)property;
  199. /// Replaces the given property on the recieving class. Useful for changing a property's attributes.
  200. + (void)flex_replaceProperty:(NSString *)name attributes:(FLEXPropertyAttributes *)attributes;
  201. @end
  202. NS_ASSUME_NONNULL_END