FLEXIvar.m 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. //
  2. // FLEXIvar.m
  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 "FLEXIvar.h"
  10. #import "FLEXRuntimeUtility.h"
  11. @interface FLEXIvar () {
  12. NSString *_flex_description;
  13. }
  14. @end
  15. @implementation FLEXIvar
  16. #pragma mark Initializers
  17. - (id)init {
  18. [NSException
  19. raise:NSInternalInconsistencyException
  20. format:@"Class instance should not be created with -init"
  21. ];
  22. return nil;
  23. }
  24. + (instancetype)ivar:(Ivar)ivar {
  25. return [[self alloc] initWithIvar:ivar];
  26. }
  27. + (instancetype)named:(NSString *)name onClass:(Class)cls {
  28. Ivar ivar = class_getInstanceVariable(cls, name.UTF8String);
  29. return [self ivar:ivar];
  30. }
  31. - (id)initWithIvar:(Ivar)ivar {
  32. NSParameterAssert(ivar);
  33. self = [super init];
  34. if (self) {
  35. _objc_ivar = ivar;
  36. [self examine];
  37. }
  38. return self;
  39. }
  40. #pragma mark Other
  41. - (NSString *)description {
  42. if (!_flex_description) {
  43. NSString *readableType = [FLEXRuntimeUtility readableTypeForEncoding:self.typeEncoding];
  44. _flex_description = [FLEXRuntimeUtility appendName:self.name toType:readableType];
  45. }
  46. return _flex_description;
  47. }
  48. - (NSString *)debugDescription {
  49. return [NSString stringWithFormat:@"<%@ name=%@, encoding=%@, offset=%ld>",
  50. NSStringFromClass(self.class), self.name, self.typeEncoding, (long)self.offset];
  51. }
  52. - (void)examine {
  53. _name = @(ivar_getName(self.objc_ivar));
  54. _typeEncoding = @(ivar_getTypeEncoding(self.objc_ivar));
  55. _type = (FLEXTypeEncoding)[_typeEncoding characterAtIndex:0];
  56. _offset = ivar_getOffset(self.objc_ivar);
  57. }
  58. - (id)getValue:(id)target {
  59. id value = nil;
  60. #ifdef __arm64__
  61. // See http://www.sealiesoftware.com/blog/archive/2013/09/24/objc_explain_Non-pointer_isa.html
  62. if (self.type == FLEXTypeEncodingObjcClass && [self.name isEqualToString:@"isa"]) {
  63. value = object_getClass(target);
  64. } else
  65. #endif
  66. if (self.type == FLEXTypeEncodingObjcObject || self.type == FLEXTypeEncodingObjcClass) {
  67. value = object_getIvar(target, self.objc_ivar);
  68. } else {
  69. void *pointer = (__bridge void *)target + self.offset;
  70. value = [FLEXRuntimeUtility
  71. valueForPrimitivePointer:pointer
  72. objCType:self.typeEncoding.UTF8String
  73. ];
  74. }
  75. return value;
  76. }
  77. - (void)setValue:(id)value onObject:(id)target {
  78. const char *typeEncodingCString = self.typeEncoding.UTF8String;
  79. if (self.type == FLEXTypeEncodingObjcObject) {
  80. object_setIvar(target, self.objc_ivar, value);
  81. } else if ([value isKindOfClass:[NSValue class]]) {
  82. // Primitive - unbox the NSValue.
  83. NSValue *valueValue = (NSValue *)value;
  84. // Make sure that the box contained the correct type.
  85. NSAssert(
  86. strcmp(valueValue.objCType, typeEncodingCString) == 0,
  87. @"Type encoding mismatch (value: %s; ivar: %s) in setting ivar named: %@ on object: %@",
  88. valueValue.objCType, typeEncodingCString, self.name, target
  89. );
  90. NSUInteger bufferSize = 0;
  91. @try {
  92. // NSGetSizeAndAlignment barfs on type encoding for bitfields.
  93. NSGetSizeAndAlignment(typeEncodingCString, &bufferSize, NULL);
  94. } @catch (NSException *exception) { }
  95. if (bufferSize > 0) {
  96. void *buffer = calloc(bufferSize, 1);
  97. [valueValue getValue:buffer];
  98. void *pointer = (__bridge void *)target + self.offset;
  99. memcpy(pointer, buffer, bufferSize);
  100. free(buffer);
  101. }
  102. }
  103. }
  104. - (id)getPotentiallyUnboxedValue:(id)target {
  105. return [FLEXRuntimeUtility
  106. potentiallyUnwrapBoxedPointer:[self getValue:target]
  107. type:self.typeEncoding.UTF8String
  108. ];
  109. }
  110. @end