#pragma mark - 1:添加方法
//注意,在这里就不能使用[self method:]进行调用了,因为我们添加的方法是在运行时才执行,而编译器只负责编译时的方法检索,一旦对一个对象没有检索到它的drive方法,就会报错,所以这里我们使用performSelector:withObject:来进行调用,保存,运行。
- (void)dynamicAddMethod {
Student*c = [[Studentalloc]init];
// [self drive];
inti =[cperformSelector:@selector(drive)withObject:@"bmw"];
NSLog(@"%d",i);
}
#pragma mark -2:归档解档
- (void) Archiver{
Student*stu = [[Studentalloc]init];
stu.name=@"zhang";
stu.age=26;
//进行归档
NSData*data = [NSKeyedArchiverarchivedDataWithRootObject:stu];
//进行反归档
Student*stu2 = [NSKeyedUnarchiverunarchiveObjectWithData:data];
NSLog(@"stu:%@,%ld",stu.name,stu.age);
NSLog(@"stu2:%@,%ld",stu2.name,stu2.age);
NSLog(@"stu改变之后=======");
stu.name=@"李四";
stu.age=100;
NSLog(@"stu:%@,%ld",stu.name,stu.age);
NSLog(@"stu2:%@,%ld",stu2.name,stu2.age);
charyname ;
objc_setAssociatedObject(stu, &yname,@22323,OBJC_ASSOCIATION_ASSIGN);
NSString* str =objc_getAssociatedObject(stu, (__bridgeconstvoid*)(stu.name));
NSLog(@"%@",str);
}
#pragma mark -3:获取修改属性
-(void)getupPP{
person*onePerson = [[personalloc]init];
unsignedintcount =0;
//1获取所有属性class_copyPropertyList(, )获取公开属性
Ivar* memberClass =class_copyIvarList([onePersonclass], &count);
for(inti =0; i
constchar*strName1 =ivar_getName(memberClass[i]);
constchar*strType =ivar_getTypeEncoding(memberClass[1]);
NSLog(@"%s--%s",strName1,strType);
}
//2:对私有变量的更改
object_setIvar(onePerson, memberClass[1],@"hehe");
object_setIvar(onePerson, memberClass[0],@"hhh");
}
#pragma mark -4:获取方法
- (void)private
{
//可以获取自己所有的方法包括私有
unsignedintoutCount =0;
Method*method =class_copyMethodList([personclass], &outCount);
for(inti =0; i
SELcls =method_getName(method[i]);
constchar* clsName =sel_getName(cls);
NSString* clss = [NSStringstringWithFormat:@"%s", clsName];
NSLog(@"%@",clss );
}
}
#pragma mark - 5:创建类和替换方法
-(void)setupUI{
////创建继承自NSObject类的People类
Class pppp =objc_allocateClassPair([Studentclass],"pppp",0);
////将People类注册到runtime中
objc_registerClassPair(pppp);
//注册test:方法选择器
SELsel =sel_registerName("test:");
//函数实现
IMPimp =imp_implementationWithBlock(^(idthis,idargs,...){
NSLog(@"方法的调用者为%@",this);
NSLog(@"参数为: %@",args);
return@"返回值测试";
});
//向People类中添加test:方法;函数签名为@@:@,
//第一个@表示返回值类型为id,
//第二个@表示的是函数的调用者类型,
//第三个:表示SEL
//第四个@表示需要一个id类型的参数
class_addMethod(pppp, sel, imp,"@@:@");
//替换People从NSObject类中继承而来的description方法
class_replaceMethod(pppp,@selector(description),imp_implementationWithBlock(^NSString*(idthis,...){
return@"haha是我";}),
"@@:");
//id p1 =[[pppp alloc]init];
idp1 = ((id(*)(id,SEL,SEL))(void*)objc_msgSend)((id)pppp,@selector(alloc),@selector(init));
////调用p1的sel选择器的方法,并传递@"???"作为参数
idresult = ((id(*)(id,SEL,void*))(void*)objc_msgSend)((id)p1, sel,@"ffff");
//输出sel方法的返回值
NSLog(@"sel方法的返回值为:%@",result);
}
#pragma mark -6:替换方法
-(void)replaceMethod{
//函数实现
IMPImp =imp_implementationWithBlock(^( ){
NSLog(@"你被替换了");
});
constchar*types;
class_replaceMethod([UILabelclass],@selector(drawTextInRect:), Imp,types);
UILabel* lb = [UILabelnew];
[lbdrawTextInRect:CGRectZero];
}
-(void)adpp{
Student* st = [Studentnew];
st.names=@"多的名字";
NSLog(@"%@",st.names);
}
分类中的代码
#pragma mark -添加方法
/*
当项目中,需要继承某一个类(subclass),但是父类中并没有提供我需要的调用方法,而我又不清楚父类中某些方法的具体实现;或者,我需要为这个类写一个分类(category),在这个分类中,我可能需要替换/新增某个方法(注意:不推荐在分类中重写方法,而且也无法通过super来获取所谓父类的方法)。大致在这两种情况下,我们可以通过class_addMethod来实现我们想要的效果。
正常的调用方法是通过消息机制(message)来实现的,那么如果类中没有找到发送的消息方法,系统就会进入找不到该方法的处理流程中,如果在这个流程中,我们加入我们所需要的新方法,就能实现运行过程中的动态添加了。这个流程或者说机制,就是Objective-C的Message Forwarding
+ (BOOL)resolveInstanceMethod:(SEL)sel
+ (BOOL)resolveClassMethod:(SEL)sel
区别在于需要添加的是静态方法还是实例方法
resolveInstanceMethod
这个函数在runtime环境下,如果没有找到该方法的实现的话就会执行。第一行判断的是传入的SEL名称是否匹配,接着调用class_addMethod方法,传入相应的参数。其中第三个参数传入的是我们添加的C语言函数的实现,也就是说,第三个参数的名称要和添加的具体函数名称一致。第四个参数指的是函数的返回值以及参数内容。
至于该类方法的返回值,在我测试的时候,无论这个BOOL值是多少,并不会影响我们的执行目标,一般返回YES即可。
使用时<<<<<<<<<<<<<<
//注意,在这里就不能使用[self method:]进行调用了,因为我们添加的方法是在运行时才执行,而编译器只负责编译时的方法检索,一旦对一个对象没有检索到它的drive方法,就会报错,所以这里我们使用performSelector:withObject:来进行调用,保存,运行。
- (void)dynamicAddMethod {
Student *c = [[Student alloc] init];
// [self drive];
int i =[c performSelector:@selector(drive) withObject:@"bmw"];
NSLog(@"%d",i);
}
使用时>>>>>>>>>>>
*/
// class_getMethodImplementation意思就是获取SEL的具体实现的指针
//向People类中添加test:方法;函数签名为@@:@,
//第一个@表示返回值类型为id,
//第二个@表示的是函数的调用者类型,
//第三个:表示SEL
//第四个@表示需要一个id类型的参数
//在我测试的时候,无论这个BOOL值是多少,并不会影响我们的执行目标,一般返回YES即可
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if(sel ==@selector(drive)) {
class_addMethod([Studentclass], sel,class_getMethodImplementation(self,@selector(startEngine:)),"@@:@");
returnNO;
}
return[superresolveInstanceMethod:sel];
}
- (int)startEngine:(NSString*)brand {
NSLog(@"my %@ car starts the engine", brand);
return5;
}
//关联的key
staticconstchar*key ="names";
- (NSString*)names
{
//根据关联的key,获取关联的值。
returnobjc_getAssociatedObject(self,key);
}
- (void)setNames:(NSString*)names
{
//第一个参数:给哪个对象添加关联
//第二个参数:关联的key,通过这个key获取
//第三个参数:关联的value
//第四个参数:关联的策略
objc_setAssociatedObject(self,key, names,OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
person 代码
- (instancetype)init
{
self= [superinit];
if(self) {
_address=@"三里屯SOHO";
self.name=@"zk";
//[self setupUI];
}
returnself;
}
- (NSString*)description
{
return[NSStringstringWithFormat:@"address: %@, name: %@",self.address,self.name];
}
- (void)sayHello
{
NSLog(@"hello ,I'm at %@",self.address);
}
- (void)interface
{
NSLog(@"I'm %@",self.name);
}