FLEXProperty.h 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. //
  2. // FLEXProperty.h
  3. // FLEX
  4. //
  5. // Derived from MirrorKit.
  6. // Created by Tanner on 6/30/15.
  7. // Copyright (c) 2015 Tanner Bennett. All rights reserved.
  8. //
  9. #import <Foundation/Foundation.h>
  10. #import "FLEXRuntimeUtility.h"
  11. #import <objc/runtime.h>
  12. @class FLEXPropertyAttributes, FLEXMethodBase;
  13. #pragma mark FLEXProperty
  14. @interface FLEXProperty : NSObject
  15. /// You may use this initializer instead of \c property:onClass: if you don't need
  16. /// to know anything about the uniqueness of this property or where it comes from.
  17. + (instancetype)property:(objc_property_t)property;
  18. /// This initializer can be used to access additional information
  19. /// in an efficient manner. That information being whether this property
  20. /// is certainly not unique and the name of the binary image which declares it.
  21. /// @param cls the class, or metaclass if this is a class property.
  22. + (instancetype)property:(objc_property_t)property onClass:(Class)cls;
  23. /// @param cls the class, or metaclass if this is a class property
  24. + (instancetype)named:(NSString *)name onClass:(Class)cls;
  25. /// Constructs a new property with the given name and attributes.
  26. + (instancetype)propertyWithName:(NSString *)name attributes:(FLEXPropertyAttributes *)attributes;
  27. /// \c 0 if the instance was created via \c +propertyWithName:attributes,
  28. /// otherwise this is the first property in \c objc_properties
  29. @property (nonatomic, readonly) objc_property_t objc_property;
  30. @property (nonatomic, readonly) objc_property_t *objc_properties;
  31. @property (nonatomic, readonly) NSInteger objc_propertyCount;
  32. @property (nonatomic, readonly) BOOL isClassProperty;
  33. /// The name of the property.
  34. @property (nonatomic, readonly) NSString *name;
  35. /// The type of the property. Get the full type from the attributes.
  36. @property (nonatomic, readonly) FLEXTypeEncoding type;
  37. /// The property's attributes.
  38. @property (nonatomic ) FLEXPropertyAttributes *attributes;
  39. /// The (likely) setter, regardless of whether the property is readonly.
  40. /// For example, this might be the custom setter.
  41. @property (nonatomic, readonly) SEL likelySetter;
  42. /// Not valid unless initialized with the owning class.
  43. @property (nonatomic, readonly) BOOL likelySetterExists;
  44. /// The (likely) getter. For example, this might be the custom getter.
  45. @property (nonatomic, readonly) SEL likelyGetter;
  46. /// Not valid unless initialized with the owning class.
  47. @property (nonatomic, readonly) BOOL likelyGetterExists;
  48. /// Whether there are certainly multiple definitions of this property,
  49. /// such as in categories in other binary images or something.
  50. /// @return Whether \c objc_property matches the return value of \c class_getProperty,
  51. /// or \c NO if this property was not created with \c property:onClass
  52. @property (nonatomic, readonly) BOOL multiple;
  53. /// @return The bundle of the image that contains this property definition,
  54. /// or \c nil if this property was not created with \c property:onClass or
  55. /// if this property is probably defined in the objc runtime.
  56. @property (nonatomic, readonly) NSString *imageName;
  57. /// For internal use
  58. @property (nonatomic) id tag;
  59. /// @return The value of this property on \c target as given by \c -valueForKey:
  60. - (id)getValue:(id)target;
  61. /// Calls into -getValue: and passes that value into
  62. /// -[FLEXRuntimeUtility potentiallyUnwrapBoxedPointer:type:]
  63. /// and returns the result
  64. - (id)getPotentiallyUnboxedValue:(id)target;
  65. /// Safe to use regardless of how the \c FLEXProperty instance was initialized.
  66. ///
  67. /// This uses \c self.objc_property if it exists, otherwise it uses \c self.attributes
  68. - (objc_property_attribute_t *)copyAttributesList:(unsigned int *)attributesCount;
  69. /// Replace the attributes of the current property in the given class,
  70. /// using the attributes in \c self.attributes
  71. ///
  72. /// What happens when the property does not exist is undocumented.
  73. - (void)replacePropertyOnClass:(Class)cls;
  74. #pragma mark Convenience getters and setters
  75. /// @return A getter for the property with the given implementation.
  76. /// @discussion Consider using the \c FLEXPropertyGetter macros.
  77. - (FLEXMethodBase *)getterWithImplementation:(IMP)implementation;
  78. /// @return A setter for the property with the given implementation.
  79. /// @discussion Consider using the \c FLEXPropertySetter macros.
  80. - (FLEXMethodBase *)setterWithImplementation:(IMP)implementation;
  81. #pragma mark FLEXMethod property getter / setter macros
  82. // Easier than using the above methods yourself in most cases
  83. /// Takes a \c FLEXProperty and a type (ie \c NSUInteger or \c id) and
  84. /// uses the \c FLEXProperty's \c attribute's \c backingIvarName to get the Ivar.
  85. #define FLEXPropertyGetter(FLEXProperty, type) [FLEXProperty \
  86. getterWithImplementation:imp_implementationWithBlock(^(id self) { \
  87. return *(type *)[self getIvarAddressByName:FLEXProperty.attributes.backingIvar]; \
  88. }) \
  89. ];
  90. /// Takes a \c FLEXProperty and a type (ie \c NSUInteger or \c id) and
  91. /// uses the \c FLEXProperty's \c attribute's \c backingIvarName to set the Ivar.
  92. #define FLEXPropertySetter(FLEXProperty, type) [FLEXProperty \
  93. setterWithImplementation:imp_implementationWithBlock(^(id self, type value) { \
  94. [self setIvarByName:FLEXProperty.attributes.backingIvar value:&value size:sizeof(type)]; \
  95. }) \
  96. ];
  97. /// Takes a \c FLEXProperty and a type (ie \c NSUInteger or \c id) and an Ivar name string to get the Ivar.
  98. #define FLEXPropertyGetterWithIvar(FLEXProperty, ivarName, type) [FLEXProperty \
  99. getterWithImplementation:imp_implementationWithBlock(^(id self) { \
  100. return *(type *)[self getIvarAddressByName:ivarName]; \
  101. }) \
  102. ];
  103. /// Takes a \c FLEXProperty and a type (ie \c NSUInteger or \c id) and an Ivar name string to set the Ivar.
  104. #define FLEXPropertySetterWithIvar(FLEXProperty, ivarName, type) [FLEXProperty \
  105. setterWithImplementation:imp_implementationWithBlock(^(id self, type value) { \
  106. [self setIvarByName:ivarName value:&value size:sizeof(type)]; \
  107. }) \
  108. ];
  109. @end