FLEXClassBuilder.m 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  1. //
  2. // FLEXClassBuilder.m
  3. // FLEX
  4. //
  5. // Derived from MirrorKit.
  6. // Created by Tanner on 7/3/15.
  7. // Copyright (c) 2015 Tanner Bennett. All rights reserved.
  8. //
  9. #import "FLEXClassBuilder.h"
  10. #import "FLEXProperty.h"
  11. #import "FLEXMethodBase.h"
  12. #import "FLEXProtocol.h"
  13. #import <objc/runtime.h>
  14. #pragma mark FLEXClassBuilder
  15. @interface FLEXClassBuilder ()
  16. @property (nonatomic) NSString *name;
  17. @end
  18. @implementation FLEXClassBuilder
  19. - (id)init {
  20. [NSException
  21. raise:NSInternalInconsistencyException
  22. format:@"Class instance should not be created with -init"
  23. ];
  24. return nil;
  25. }
  26. #pragma mark Initializers
  27. + (instancetype)allocateClass:(NSString *)name {
  28. return [self allocateClass:name superclass:NSObject.class];
  29. }
  30. + (instancetype)allocateClass:(NSString *)name superclass:(Class)superclass {
  31. return [self allocateClass:name superclass:superclass extraBytes:0];
  32. }
  33. + (instancetype)allocateClass:(NSString *)name superclass:(Class)superclass extraBytes:(size_t)bytes {
  34. NSParameterAssert(name);
  35. return [[self alloc] initWithClass:objc_allocateClassPair(superclass, name.UTF8String, bytes)];
  36. }
  37. + (instancetype)allocateRootClass:(NSString *)name {
  38. NSParameterAssert(name);
  39. return [[self alloc] initWithClass:objc_allocateClassPair(Nil, name.UTF8String, 0)];
  40. }
  41. + (instancetype)builderForClass:(Class)cls {
  42. return [[self alloc] initWithClass:cls];
  43. }
  44. - (id)initWithClass:(Class)cls {
  45. NSParameterAssert(cls);
  46. self = [super init];
  47. if (self) {
  48. _workingClass = cls;
  49. _name = NSStringFromClass(_workingClass);
  50. }
  51. return self;
  52. }
  53. - (NSString *)description {
  54. return [NSString stringWithFormat:@"<%@ name=%@, registered=%d>",
  55. NSStringFromClass(self.class), self.name, self.isRegistered];
  56. }
  57. #pragma mark Building
  58. - (NSArray *)addMethods:(NSArray *)methods {
  59. NSParameterAssert(methods.count);
  60. NSMutableArray *failed = [NSMutableArray new];
  61. for (FLEXMethodBase *m in methods) {
  62. if (!class_addMethod(self.workingClass, m.selector, m.implementation, m.typeEncoding.UTF8String)) {
  63. [failed addObject:m];
  64. }
  65. }
  66. return failed;
  67. }
  68. - (NSArray *)addProperties:(NSArray *)properties {
  69. NSParameterAssert(properties.count);
  70. NSMutableArray *failed = [NSMutableArray new];
  71. for (FLEXProperty *p in properties) {
  72. unsigned int pcount;
  73. objc_property_attribute_t *attributes = [p copyAttributesList:&pcount];
  74. if (!class_addProperty(self.workingClass, p.name.UTF8String, attributes, pcount)) {
  75. [failed addObject:p];
  76. }
  77. free(attributes);
  78. }
  79. return failed;
  80. }
  81. - (NSArray *)addProtocols:(NSArray *)protocols {
  82. NSParameterAssert(protocols.count);
  83. NSMutableArray *failed = [NSMutableArray new];
  84. for (FLEXProtocol *p in protocols) {
  85. if (!class_addProtocol(self.workingClass, p.objc_protocol)) {
  86. [failed addObject:p];
  87. }
  88. }
  89. return failed;
  90. }
  91. - (NSArray *)addIvars:(NSArray *)ivars {
  92. NSParameterAssert(ivars.count);
  93. NSMutableArray *failed = [NSMutableArray new];
  94. for (FLEXIvarBuilder *ivar in ivars) {
  95. if (!class_addIvar(self.workingClass, ivar.name.UTF8String, ivar.size, ivar.alignment, ivar.encoding.UTF8String)) {
  96. [failed addObject:ivar];
  97. }
  98. }
  99. return failed;
  100. }
  101. - (Class)registerClass {
  102. if (self.isRegistered) {
  103. [NSException raise:NSInternalInconsistencyException format:@"Class is already registered"];
  104. }
  105. objc_registerClassPair(self.workingClass);
  106. return self.workingClass;
  107. }
  108. - (BOOL)isRegistered {
  109. return objc_lookUpClass(self.name.UTF8String) != nil;
  110. }
  111. @end
  112. #pragma mark FLEXIvarBuilder
  113. @implementation FLEXIvarBuilder
  114. + (instancetype)name:(NSString *)name size:(size_t)size alignment:(uint8_t)alignment typeEncoding:(NSString *)encoding {
  115. return [[self alloc] initWithName:name size:size alignment:alignment typeEncoding:encoding];
  116. }
  117. - (id)initWithName:(NSString *)name size:(size_t)size alignment:(uint8_t)alignment typeEncoding:(NSString *)encoding {
  118. NSParameterAssert(name); NSParameterAssert(encoding);
  119. NSParameterAssert(size > 0); NSParameterAssert(alignment > 0);
  120. self = [super init];
  121. if (self) {
  122. _name = name;
  123. _encoding = encoding;
  124. _size = size;
  125. _alignment = alignment;
  126. }
  127. return self;
  128. }
  129. @end