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

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,287评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,346评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,277评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,132评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,147评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,106评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,019评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,862评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,301评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,521评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,682评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,405评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,996评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,651评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,803评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,674评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,563评论 2 352

推荐阅读更多精彩内容