runtime完全整理

#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);

}

你可能感兴趣的:(runtime完全整理)