在上一篇KVO的实现中用到了动态的创建类,添加成员变量等方法,这一篇说说这些方法的使用。
父类Person
@interface Person : NSObject
@property (nonatomic, copy) NSString * name;
@property (nonatomic, assign) NSInteger age;
- (void)work;
@end
@implementation Person
- (void)setName:(NSString *)name{
_name = name;
NSLog(@"Person ---> setName %@",name);
}
- (void)setAge:(NSInteger)age{
_age = age;
NSLog(@"Person ---> setAge %ld",age);
}
- (void)work{
NSLog(@"Person ---> work");
}
@end
1.动态的创建一个类,用到了下面这个方法:
// ex:创建一个Student类,继承自Person
const char * className = [@"Student" cStringUsingEncoding:NSUTF8StringEncoding];
// param1:新创建类的父类
// param2:新创建类的类名
// param3:默认为0
Class student = objc_allocateClassPair([Person class], className, 0);
// add iVar add method ...
objc_registerClassPair(student);
- @note To create a new class, start by calling \c objc_allocateClassPair.
- Then set the class's attributes with functions like \c class_addMethod and \c class_addIvar.
- When you are done building the class, call \c objc_registerClassPair. The new class is now ready for use.
为这个新创建的类添加方法和成员变量,并且注册这个类。
2.添加成员变量
// add iVar
class_addIvar(student, "_name",sizeof(NSString *), log2(sizeof(NSString *)), @encode(NSString *));
class_addIvar(student, "_age", sizeof(NSInteger), log2(sizeof(NSInteger)), @encode(NSInteger));
This function may only be called after objc_allocateClassPair and before objc_registerClassPair. Adding an instance variable to an existing class is not supported.
返回YES,添加成功,返回NO,添加失败,说明该类中已经存在这个名称。它的调用是在objc_allocateClassPair
之后,objc_registerClassPair
之前,给一个存在的类添加实例变量是不允许的。
我们尝试着给Person添加address
![](https://img.haomeiwen.com/i5344321/1d88e0875b4887f0.png)
3.添加方法
通过class_addMethod(Class cls, SEL name, IMP imp, const char *types)
方法添加,参数依次为:添加方法的类,方法名,方法实现,方法参数的描述。
class_addMethod will add an override of a superclass's implementation, but will not replace an existing implementation in this class. To change an existing implementation, use method_setImplementation.
通过这个方法会重写父类的实现,需要改变本类方法实现,通过方法method_setImplementation
.
static void stu_setName(id self, SEL _cmd, id value){
NSLog(@"student ---> stu_setName %@",value);
}
const char * types = method_getTypeEncoding(class_getInstanceMethod(
[Person class], @selector(setName:)));
BOOL result1 = class_addMethod(student, @selector(setName:), (IMP)(stu_setName), types);
BOOL result2 = class_addMethod(student, @selector(setName:), (IMP)(stu_setName), types);
NSLog(@"result1: %d, result2: %d",result1,result2);
id stu = [[student alloc] init];
[stu setValue:@"小鲨鱼" forKey:@"name"];
打印结果:
result1: 1, result2: 0
student ---> stu_setName 小鲨鱼
4.重写本类中的方法
通过方法method_setImplementation(Method m, IMP imp)
返回类型IMP
,方法m之前的实现.
static void study(id self, SEL _cmd){
NSLog(@"student ---> study.");
}
static void play (id self, SEL _cmd){
NSLog(@"student ---> play.");
}
class_addMethod(student, @selector(study), (IMP)(study), nil);
id stu = [[student alloc] init];
[stu performSelector:@selector(study)];
Method studyMethod = class_getInstanceMethod(student, @selector(study));
method_setImplementation(studyMethod, (IMP)(play));
[stu performSelector:@selector(study)];
打印结果:
student ---> study.
student ---> play.
在调用study的方法的时候打印的是play的结果,调换了方法的实现。method_exchangeImplementations(Method m1, Method m2)
,可能也是通过这种方法实现m1,m2的交换。
5.添加属性
objc_property_attribute_t type = { "T", "@\"NSString\"" };
objc_property_attribute_t attrs[] = {type};
BOOL result4 = class_addProperty([student class], "number", attrs, 1);
[stu setValue:@"2018" forKey:@"number"];
NSLog(@"------ %@ , %d",[stu valueForKey:@"number"],result4);
打印结果
------ 2018 , 1
网友评论