自己封装的BGSrBGRuntimekitBGR框架

runtime ,小伙伴们在面试的会经常问到,runtime 里面的获取目标类的类名,方法名等方法一般是封装一般类共用方法的基础。所以我们有必要理清运行时到底是什么。它有什么用途,即方法用途。

程序员有时候会在什么东西应该在编译的时候加载进来以及什么东西该在运行的时候使用之间做出抉择,前者有时候被称为编译时期。

一段时间以来,技术类作者都拒绝使用"运行时刻"作为一种术语,他们坚持类似于"一个程序在运行"之类的说法,用以避免需要一个专门的术语。后来,这个术语逐渐地蔓延到通常的应用中。Objective-C Runtime 是开源的

Objective-C 是开源的,任何时候你都能从 http://opensource.apple.com. 获取。事实上查看 Objective-C 源码是我理解它是如何工作的第一种方式,在这个问题上要比读苹果的文档要好。你可以下载适合 Mac OS X 10.6.2 的 objc4-437.1.tar.gz。(译注:最新objc4-551.1.tar.gz)

Objective-C 是面相运行时的语言(runtime oriented language),就是说它会尽可能的把编译和链接时要执行的逻辑延迟到运行时。这就给了你很大的灵活性,你可以按需要把消息重定向给合适的对象,你甚 至可以交换方法的实现,等等(译注:在 Objective-C 中调用一个对象的方法可以看成向一个对象发送消息, Method Swizzling 具体实现可以参看 jrswizzle )。这就需要使用 runtime,runtime 可以做对象自省查看他们正在做的和不能做的(don't respond to)并且合适的分发消息(译注:感兴趣的同学可以查看 NSObject 类的 – forwardingTargetForSelector: 和 – forwardInvocation: 方法。P.S. 不是 NSObject 协议! )。如果我们和 C 这样的语言对比。在 C 里,你从 main() 方法开始写然后就是从上到下的写逻辑了并按你写代码的顺序执行程序。一个 C 的结构体不能转发函数执行请求到其他的目标上(other targets)。很可能你的程序是这样的:

所以我们现在总结一下运行时的主要用途。

1.//获取变量列表数组

NSArray *varlist=[BGSRuntimeKit fetchIvarList:[TestClass class]];

NSLog(@"varlist:%@",varlist);

此方法对于抽象类,封装特别有用,一个抽象类你不知道,这个类实例到底有多少属性。那不妨用我封装BGSRuntimekit获取变量列表的方法,获取此数组。现在看一下此方法的具体封装源码

/**

动态获取类的变量列表

@param class 要获取列表的类

@return 所有变量的列表数组

*/

+(NSArray *)fetchIvarList:(Class)class {

unsigned int outCount =0;

NSArray *varListArray;

NSMutableArray *mListArray=[NSMutableArray array];

Ivar *ivarList=class_copyIvarList(class, &outCount);

for (int i=0; i<outCount;i++){

const char *ivarName=ivar_getName(ivarList[i]);

const char *ivarType=ivar_getTypeEncoding(ivarList[i]);

NSMutableDictionary *ivarListDic=[[NSMutableDictionary alloc]initWithCapacity:outCount];

[ivarListDic setObject:[NSString stringWithUTF8String:ivarName] forKey:@"name"];

[ivarListDic setObject:[NSString stringWithUTF8String:ivarType] forKey:@"type"];

[mListArray addObject:ivarListDic];

}

varListArray=[mListArray copy];

return varListArray;

}


2.第二个用途是,获取目标类的 类名,此方法是最简单的,

**

返回类名

@param cls 要返回类名的class

@return 返回类名的字符串

*/

+ (NSString *)fetchClassName:(Class)cls  {

const char *className=class_getName(cls);

NSString *clsName=[NSString stringWithUTF8String:className];

return clsName;

}

3.获取目标类的属性列表 

/**

获取某个类的属性列表

@param cls 目标类

@return 此类的属性列表数组

*

+(NSArray *)fetchPropertyList:(Class)cls {

NSArray *propertyListArray;

unsigned int outcount=0;

objc_property_t *propertyList=class_copyPropertyList(cls, &outcount);

NSMutableArray *mutableList=[NSMutableArray arrayWithCapacity:outcount];

for (int i=0; i<outcount;i++){

const char *propertyName=property_getName(propertyList[i]);

[mutableList addObject:[NSString stringWithUTF8String:propertyName]];

}

propertyListArray=[mutableList copy];

free(propertyList);

return propertyListArray;

}

后台打印属性列表

4.获取目标类的属性类型列表,在封装类的时候,往往不知道抽象类 到底有数据属性,属性类型是什么,对于不通类型,我们应该怎么应对。方法4和方法3,往往结合使用,既可以查看属性名字,又可以查找属性类型。

/**

获取目标类的属性类型列表

@param cls 目标类

@return 属性类型列表的数组

*/

+(NSArray *)fetchPropertyTypeList:(Class)cls{

unsigned int outcount=0;

objc_property_t *propertyList=class_copyPropertyList(cls, &outcount);

NSMutableArray *marray=[NSMutableArray arrayWithCapacity:outcount];

for (int i=0; i<outCount;i++){

const char *propertyAttributes=property_getAttributes(propertyList[i]);

NSString *attributes=[NSString stringWithUTF8String:propertyAttributes];

NSLog(@"attributes:%@",attributes);

NSMutableString *mattributes=[NSMutableString stringWithString:attributes];

NSArray *componentArray=[mattributes componentsSeparatedByString:@","];

NSString *firstTypeWord=componentArray[0];

NSString *type=@"";

NSLog(@"firstTypeWord:%@",firstTypeWord);

if ([firstTypeWord containsString:@"@"]) {

NSMutableString *mtypeStr=[NSMutableString stringWithString:firstTypeWord];

NSArray *compsArray=[mtypeStr componentsSeparatedByString:@"\""];

type=compsArray[1];

NSLog(@"type:%@",type);

}else{

NSString  *typeShort=[firstTypeWord substringFromIndex:1];

//下面是对属性类型的简称恢复成全城,方便辨别

if ([typeShort isEqualToString:@"i"]) {

type=@"int";

}

else if ([typeShort isEqualToString:@"B"]){

type=@"BOOL";

}

else if ([typeShort isEqualToString:@"f"]){

type=@"float";

}

else if ([typeShort isEqualToString:@"d"]){

type=@"double";

}

else if ([typeShort isEqualToString:@"q"]){

type=@"NSInteger";

}

else {

type=@"not know type";

}

}

NSLog(@"type:%@",type);

[marray addObject:type];

}

//记住此处一定释放调属性列表

free(propertyList);

return [marray copy];

}

后台打印属性类型列表




5.获取目标类的方法列表,

/**

获取目标类的方法列表

@param cls 目标类

@return 方法列表的数组

*/

+ (NSArray *)fetchMethodList:(Class)cls {

unsigned int outcount=0;

Method *mothodList=class_copyMethodList(cls, &outcount);

NSMutableArray *methodNameArry=[NSMutableArray arrayWithCapacity:outcount];

for (int i=0; i<outCount;i++){

Method m=mothodList[i];

SEL methodName=method_getName(m);

[methodNameArry addObject:NSStringFromSelector(methodName)];

}

free(mothodList);

return [methodNameArry copy];

}

后台打印方法列表




6.获取目标类的协议列表;有些类使用了哪些协议,利用此方法也能一目了然。

/**

获取目标类的协议列表

@param cls 目标类

@return 目标类的协议列表数组

*/

+ (NSArray *)fetchProtocolList:(Class)cls {

unsigned int count=0;

__unsafe_unretained Protocol **protocolList=class_copyProtocolList(cls, &count);

NSMutableArray *protocolArray=[NSMutableArray arrayWithCapacity:count];

for (int i=0; i< count; i++) {

Protocol *protocol=protocolList[i];

const char *protocolName=protocol_getName(protocol);

[protocolArray addObject:[NSString stringWithUTF8String:protocolName]];

}

free(protocolList);

return [protocolArray copy];

}

7.为目标类添加动态方法,这个方法经常用到,有些方法我不是写程静态,我是动态加载。要想动态调用某个方法必须使用performSelector方法,这样才能动态调用,动态生成方法。

/**

为目标类添加动态方法

@param class 目标类

@param methodSel 要添加的方法

@param impMethod 实际实现的方法

*/

+ (void)addMethod: (Class)class  method:(SEL)methodSel ImpMethod:(SEL)impMethod {

BOOL tag=NO;

Method method=class_getInstanceMethod(class, impMethod);

IMP methodImp=method_getImplementation(method);

const char *type=method_getTypeEncoding(method);

tag=class_addMethod(class, methodSel, methodImp, type);

if (tag) {

NSLog(@"addmethod successly");

}else{

NSLog(@"has the same name implemation method");

}

}

8.与此方法类似的,还有为目标类动态交换方法。

/**

为目标类动态交换方法

@param cls 目标类

@param fM 此类的第一个方法

@param sM 此类的第二个方法

*/

+ (void) methodSwap:(Class)cls firstMethod:(SEL)fM SecondMethod:(SEL)sM {

Method firstMethod= class_getInstanceMethod(cls, fM);

Method secondMethod=class_getInstanceMethod(cls, sM);

method_exchangeImplementations(firstMethod, secondMethod);

}

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

推荐阅读更多精彩内容