FLEXRuntimeUtility.h 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159
  1. //
  2. // FLEXRuntimeUtility.h
  3. // Flipboard
  4. //
  5. // Created by Ryan Olson on 6/8/14.
  6. // Copyright (c) 2014 Flipboard. All rights reserved.
  7. //
  8. #import <Foundation/Foundation.h>
  9. #import <objc/runtime.h>
  10. extern const unsigned int kFLEXNumberOfImplicitArgs;
  11. // See https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtPropertyIntrospection.html#//apple_ref/doc/uid/TP40008048-CH101-SW6
  12. extern NSString *const kFLEXPropertyAttributeKeyTypeEncoding;
  13. extern NSString *const kFLEXPropertyAttributeKeyBackingIvarName;
  14. extern NSString *const kFLEXPropertyAttributeKeyReadOnly;
  15. extern NSString *const kFLEXPropertyAttributeKeyCopy;
  16. extern NSString *const kFLEXPropertyAttributeKeyRetain;
  17. extern NSString *const kFLEXPropertyAttributeKeyNonAtomic;
  18. extern NSString *const kFLEXPropertyAttributeKeyCustomGetter;
  19. extern NSString *const kFLEXPropertyAttributeKeyCustomSetter;
  20. extern NSString *const kFLEXPropertyAttributeKeyDynamic;
  21. extern NSString *const kFLEXPropertyAttributeKeyWeak;
  22. extern NSString *const kFLEXPropertyAttributeKeyGarbageCollectable;
  23. extern NSString *const kFLEXPropertyAttributeKeyOldStyleTypeEncoding;
  24. typedef NS_ENUM(NSUInteger, FLEXPropertyAttribute) {
  25. FLEXPropertyAttributeTypeEncoding = 'T',
  26. FLEXPropertyAttributeBackingIvarName = 'V',
  27. FLEXPropertyAttributeCopy = 'C',
  28. FLEXPropertyAttributeCustomGetter = 'G',
  29. FLEXPropertyAttributeCustomSetter = 'S',
  30. FLEXPropertyAttributeDynamic = 'D',
  31. FLEXPropertyAttributeGarbageCollectible = 'P',
  32. FLEXPropertyAttributeNonAtomic = 'N',
  33. FLEXPropertyAttributeOldTypeEncoding = 't',
  34. FLEXPropertyAttributeReadOnly = 'R',
  35. FLEXPropertyAttributeRetain = '&',
  36. FLEXPropertyAttributeWeak = 'W'
  37. };
  38. typedef NS_ENUM(char, FLEXTypeEncoding) {
  39. FLEXTypeEncodingNull = '\0',
  40. FLEXTypeEncodingUnknown = '?',
  41. FLEXTypeEncodingChar = 'c',
  42. FLEXTypeEncodingInt = 'i',
  43. FLEXTypeEncodingShort = 's',
  44. FLEXTypeEncodingLong = 'l',
  45. FLEXTypeEncodingLongLong = 'q',
  46. FLEXTypeEncodingUnsignedChar = 'C',
  47. FLEXTypeEncodingUnsignedInt = 'I',
  48. FLEXTypeEncodingUnsignedShort = 'S',
  49. FLEXTypeEncodingUnsignedLong = 'L',
  50. FLEXTypeEncodingUnsignedLongLong = 'Q',
  51. FLEXTypeEncodingFloat = 'f',
  52. FLEXTypeEncodingDouble = 'd',
  53. FLEXTypeEncodingLongDouble = 'D',
  54. FLEXTypeEncodingCBool = 'B',
  55. FLEXTypeEncodingVoid = 'v',
  56. FLEXTypeEncodingCString = '*',
  57. FLEXTypeEncodingObjcObject = '@',
  58. FLEXTypeEncodingObjcClass = '#',
  59. FLEXTypeEncodingSelector = ':',
  60. FLEXTypeEncodingArrayBegin = '[',
  61. FLEXTypeEncodingArrayEnd = ']',
  62. FLEXTypeEncodingStructBegin = '{',
  63. FLEXTypeEncodingStructEnd = '}',
  64. FLEXTypeEncodingUnionBegin = '(',
  65. FLEXTypeEncodingUnionEnd = ')',
  66. FLEXTypeEncodingQuote = '\"',
  67. FLEXTypeEncodingBitField = 'b',
  68. FLEXTypeEncodingPointer = '^',
  69. FLEXTypeEncodingConst = 'r'
  70. };
  71. #define FLEXEncodeClass(class) ("@\"" #class "\"")
  72. #define FLEXEncodeObject(obj) (obj ? [NSString stringWithFormat:@"@\"%@\"", [obj class]].UTF8String : @encode(id))
  73. #define PropertyKey(suffix) kFLEXPropertyAttributeKey##suffix : @""
  74. #define PropertyKeyGetter(getter) kFLEXPropertyAttributeKeyCustomGetter : NSStringFromSelector(@selector(getter))
  75. #define PropertyKeySetter(setter) kFLEXPropertyAttributeKeyCustomSetter : NSStringFromSelector(@selector(setter))
  76. /// Takes: min iOS version, property name, target class, property type, and a list of attributes
  77. #define FLEXRuntimeUtilityTryAddProperty(iOS_atLeast, name, cls, type, ...) ({ \
  78. if (@available(iOS iOS_atLeast, *)) { \
  79. NSMutableDictionary *attrs = [NSMutableDictionary dictionaryWithDictionary:@{ \
  80. kFLEXPropertyAttributeKeyTypeEncoding : @(type), \
  81. __VA_ARGS__ \
  82. }]; \
  83. [FLEXRuntimeUtility \
  84. tryAddPropertyWithName:#name \
  85. attributes:attrs \
  86. toClass:cls \
  87. ]; \
  88. } \
  89. })
  90. /// Takes: min iOS version, property name, target class, property type, and a list of attributes
  91. #define FLEXRuntimeUtilityTryAddNonatomicProperty(iOS_atLeast, name, cls, type, ...) \
  92. FLEXRuntimeUtilityTryAddProperty(iOS_atLeast, name, cls, @encode(type), PropertyKey(NonAtomic), __VA_ARGS__);
  93. /// Takes: min iOS version, property name, target class, property type (class name), and a list of attributes
  94. #define FLEXRuntimeUtilityTryAddObjectProperty(iOS_atLeast, name, cls, type, ...) \
  95. FLEXRuntimeUtilityTryAddProperty(iOS_atLeast, name, cls, FLEXEncodeClass(type), PropertyKey(NonAtomic), __VA_ARGS__);
  96. @interface FLEXRuntimeUtility : NSObject
  97. // General Helpers
  98. + (BOOL)pointerIsValidObjcObject:(const void *)pointer;
  99. /// Unwraps raw pointers to objects stored in NSValue, and re-boxes C strings into NSStrings.
  100. + (id)potentiallyUnwrapBoxedPointer:(id)returnedObjectOrNil type:(const FLEXTypeEncoding *)returnType;
  101. /// Some fields have a name in their encoded string (e.g. \"width\"d)
  102. /// @return the offset to skip the field name, 0 if there is no name
  103. + (NSUInteger)fieldNameOffsetForTypeEncoding:(const FLEXTypeEncoding *)typeEncoding;
  104. /// Given name "foo" and type "int" this would return "int foo", but
  105. /// given name "foo" and type "T *" it would return "T *foo"
  106. + (NSString *)appendName:(NSString *)name toType:(NSString *)typeEncoding;
  107. /// @return The class hierarchy for the given object or class,
  108. /// from the current class to the root-most class.
  109. + (NSArray<Class> *)classHierarchyOfObject:(id)objectOrClass;
  110. /// Used to describe an object in brief within an explorer row
  111. + (NSString *)summaryForObject:(id)value;
  112. + (NSString *)safeDescriptionForObject:(id)object;
  113. + (NSString *)safeDebugDescriptionForObject:(id)object;
  114. // Property Helpers
  115. + (BOOL)tryAddPropertyWithName:(const char *)name
  116. attributes:(NSDictionary<NSString *, NSString *> *)attributePairs
  117. toClass:(__unsafe_unretained Class)theClass;
  118. + (NSArray<NSString *> *)allPropertyAttributeKeys;
  119. // Method Helpers
  120. + (NSArray *)prettyArgumentComponentsForMethod:(Method)method;
  121. // Method Calling/Field Editing
  122. + (id)performSelector:(SEL)selector onObject:(id)object;
  123. + (id)performSelector:(SEL)selector
  124. onObject:(id)object
  125. withArguments:(NSArray *)arguments
  126. error:(NSError * __autoreleasing *)error;
  127. + (NSString *)editableJSONStringForObject:(id)object;
  128. + (id)objectValueFromEditableJSONString:(NSString *)string;
  129. + (NSValue *)valueForNumberWithObjCType:(const char *)typeEncoding fromInputString:(NSString *)inputString;
  130. + (void)enumerateTypesInStructEncoding:(const char *)structEncoding
  131. usingBlock:(void (^)(NSString *structName,
  132. const char *fieldTypeEncoding,
  133. NSString *prettyTypeEncoding,
  134. NSUInteger fieldIndex,
  135. NSUInteger fieldOffset))typeBlock;
  136. + (NSValue *)valueForPrimitivePointer:(void *)pointer objCType:(const char *)type;
  137. #pragma mark - Metadata Helpers
  138. + (NSString *)readableTypeForEncoding:(NSString *)encodingString;
  139. @end