FLEXClassBuilder.m 4.4 KB

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