Runtime -----那些被忽略的技能
有人说现在的程序员都被惯坏了,尤其使用一些面向对象的语言开发的时候,只是简单的调用一些系统封装好的接口或者是调用一些“便利的”第三方,对于一个程序的真正实现有了解吗???又有多少了解呢???就单单的拿Objective-c 来说,确实感觉它无所不能,神马都可以做!大到整个工程文件的整合,内存的自动管理,小到图层动画的应用,界面的切换,使用几个函数就能完成,然而它的内部实现,具体如何管理的就不是那么清晰明了了。所以有时候感觉自己能用动画实现很炫酷的效果,然而主要的还是对函数的使用,对对象的操作。这也是面向对象的优势,但对程序原来讲,了解一个程序内部的真正实现还是挺有意思的比如说OC中的代理,OC中没有多继承,那通过代理实现多继承,它是怎么实现的呢?在OC 中就有这么一个特性 Runtime,它有时候像空气一样无时无刻不在,但要懂得如何运用了就可以在这个充满雾霾的空气中呼吸新鲜的空气了~但你也要运用得当,否则会氧中毒的~~
Runtime在OC中是一种运行时库在Objective-C 1.0的时候主要是使用C和汇编写的库,在Objective-C 2.0的时候使用的是C++对其进行的实现一般我们在实现的时候用到Runtime最多的也就是通过遍历类中的所有的实例变量,实现自动的归档---反归档好了,直接上代码:

Ivar *ivars = class_copyIvarList([self class], &count); // 反归档时调用
-(instancetype)initWithCoder:(NSCoder *)aDecoder { // self = [super init]; self = [self init]; if (self) {
// 若直接采用一般的方法 :----- 属性赋值
//
// self.name = [aDecoder decodeObjectForKey:@"name"];
// self.gender = [aDecoder decodeObjectForKey:@"gender"];
// self.age = [aDecoder decodeIntegerForKey:@"age"];
// self.hobby = [aDecoder decodeObjectForKey:@"hobby"];
// self.nickName = [aDecoder decodeObjectForKey:@"nickName"]; // 使用 Runtime 进行反归档处理
unsigned int ivarCount = 0; Ivar * ivarArray = class_copyIvarList([self class], &ivarCount); for (int i = 0; i < ivarCount; i++) {
NSString * varName =[NSString stringWithUTF8String:ivar_getName(ivarArray[i])]; id value = [aDecoder decodeObjectForKey:varName];
[self setValue:value forKey:varName]; }
free(ivarArray); }
return self; } // 归档时调用
-(void)encodeWithCoder:(NSCoder *)aCoder
{ // [aCoder encodeObject:self.name forKey:@"name"];
//
// [aCoder encodeObject:self.gender forKey:@"gender"];
//
// [aCoder encodeInteger:self.age forKey:@"age"];
//
// [aCoder encodeObject:self.hobby forKey:@"hobby"];
//
// [aCoder encodeObject:self.nickName forKey:@"nickName"]; unsigned int ivarCount = 0; Ivar * ivarArray = class_copyIvarList([self class], &ivarCount); // 使用KVC进行取值在归档encode for (int i = 0; i < ivarCount; i++) {
// C 语言的字符串转换成NSString NSString * varName = [NSString stringWithUTF8String:ivar_getName(ivarArray[i])]; // 使用KVC 取值 再编码 id value =[self valueForKey:varName];
// 归档
[aCoder encodeObject:value forKey:varName]; } } // 对P2进行归档
NSData * p2Data = [NSKeyedArchiver archivedDataWithRootObject:p2]; // NSLog(@"%@",p2Data); // 进行反归档 转换成对象 Person * p3 = [NSKeyedUnarchiver unarchiveObjectWithData:p2Data]; // NSLog(@"%@",p3.name);

RunTime 的归档反归档适用于归档对象属性较多的情况,可以减少代码量,逻辑更清晰。这种方式一般来说用的比较多,除此之外一些基本的使用方法也是比较常用的,比如说:

//使用运行时需要导入头文件 #import <objc/objc-runtime.h>
//或者直接引入: #include <objc/runtime.h> #include <objc/message.h> Method methodA = class_getInstanceMethod([self class], @selector(testA)); Method methodB = class_getInstanceMethod([self class], @selector(testB)); // 交换AB的方法实现 method_exchangeImplementations(methodA, methodB);

当然在Xcode在默认是不使用Runtime的需要调整一个地方:如下图:
这样就可以,还有获取某个类中的所有实例变量链表:

// 实例变量的个数 unsigned int ivarCount = 0; Ivar * ivaArray = class_copyIvarList([类名 class], &ivarCount); for (int i = 0; i < ivarCount; i++) { Ivar var = ivaArray[i]; // 输出实例变量的名称和类型 NSLog(@"%s,%s",ivar_getName(var),ivar_getTypeEncoding(var)); }// 释放指针
free(ivaArray);

获取某个类中的所有的实例方法:

unsigned int methodCount = 0; Method * methodArray = class_copyMethodList([Person class], &methodCount); for (int i = 0; i < methodCount; i++) { Method m = methodArray [i]; // 输出方法的名字和方法的类型编码
NSLog(@"%s,%s",sel_getName(method_getName(m)),method_getTypeEncoding(m)); }

其实Runtime的消息驱动机制是和常见的,除此之外还有动态绑定,具体的动态绑定有两个重要的方法,代码写的很详细:

// 动态绑定 +(BOOL)resolveClassMethod:(SEL)sel { // 输出 方法名 和所在的行数
NSLog(@"%s,%d",__FUNCTION__,__LINE__); // 定义block添加类方法 void (^resolveClassBlock)(id,SEL) = ^(id receiver,SEL objc_cmd){ NSLog(@"%s,类的方法未实现,执行此段",sel_getName(objc_cmd)); }; if (sel == @selector(heiheihei)) { // 调用block IMP blockIMP = imp_implementationWithBlock(resolveClassBlock); // 添加一个类方法
class_addMethod(object_getClass([self class]), sel, blockIMP, "v@:");
} return [super resolveClassMethod:sel]; } // 动态绑定
+(BOOL)resolveInstanceMethod:(SEL)sel { NSLog(@"%s,%d",__FUNCTION__,__LINE__); // 定义block添加实例方法 // 接受者 选标
void(^resolveBlock)(id , SEL) = ^(id receiver, SEL objc_cmd) { NSLog(@"%s,实例方法未实现,会执行此处代码。",sel_getName(objc_cmd)); }; if (sel == @selector(aaacccddd)) {
// 获取实现的bolck的地址
IMP blockIMP = imp_implementationWithBlock(resolveBlock); // 第四个参数函数的类型
class_addMethod([self class], sel, blockIMP, "v@:"); } return [super resolveInstanceMethod:sel]; }

那么到了最后的重头戏了, 在Objective-C程序中模拟多重继承就是通过消息转发机制实现的,使得一个对象通过转发来响应消息,看起来就象该对象从别的类那借来了或者”继承“了方法实现一样:具体的需要实现这两种方法进行消息的转发:
-methodSignatureForSelector:
-forwardInvocation: 具体代码如下:

//得到方法的签名
-(NSMethodSignature * )methodSignatureForSelector:(SEL)aSelector { NSMethodSignature * sig = [super methodSignatureForSelector:aSelector]; if (!sig) { WS * ws = [[WS alloc]init]; sig = [ws methodSignatureForSelector:aSelector];
}
return sig; } -(void)forwardInvocation:(NSInvocation *)anInvocation { // 方法自动执行 对消息进行转发 // 如果 本类调用 study 时 则要对方法进行转发
if (anInvocation.selector == @selector(study)) { [anInvocation invokeWithTarget:[WS new]]; } } [p2 performSelector:@selector(study)];

其实这就是Objective-C中实现代理的原理,通过这些简单的实现可以在进行相应的优化,可以开辟子线程对消息进行转发等优化方法;
最后在分享一个好玩的小技巧:
更改系统的状态栏如下:
只需在Appdelegate中作如下处理:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
UIApplication *thisApp = [UIApplication sharedApplication];
Ivar statusVar = class_getInstanceVariable([thisApp class], "_statusBar");
id statusBar = object_getIvar(thisApp, statusVar);
Ivar statusBackViewVar = class_getInstanceVariable([statusBar class], "_foregroundView");
id statusBackView = object_getIvar(statusBar, statusBackViewVar);
NSArray *viewArray = [statusBackView subviews]; UIImageView *imageView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 3, 43, 15)];
imageView.backgroundColor = [UIColor whiteColor];
imageView.image = [UIImage imageNamed:@"替换成自己喜欢的图片"];
[viewArray[0] addSubview:imageView];
return YES;
}

这样自己的个性化状态栏就有了~~~~
欢迎转载,请注明转载和原文出处:http://www.cnblogs.com/windsSunShine/
Runtime -----那些被忽略的技能的更多相关文章
- 你get了无数技能,为什么一事无成
前几日看到阮一峰老师的发的一句话,颇有感慨,「你只是坐在电脑前,往网上发表了一段文字或者一张图片,随便什么,就能够接触到多少陌生的灵魂.这就是我热爱互联网的原因」.我打心底认为这是一个最好的时代, ...
- 你 get 了无数技能,为什么一事无成
前 几日看到阮一峰老师的发的一句话,颇有感慨,「你只是坐在电脑前,往网上发表了一段文字或者一张图片,随便什么,就能够接触到多少陌生的灵魂.这就是我热 爱互联网的原因」.我打心底认为这是一个最好的时代, ...
- 专访笨叔叔:2019年可能是Linux年?(转)
链接:https://zhuanlan.zhihu.com/p/57815479 2017年9月<奔跑吧 Linux内核>一书出版后得到了广大Linux从业人员和爱好者(特别是从事Linu ...
- 基于swoole+Redis的消息实时推送通知
swoole+Redis将实时数据的推送 一 实现功能 设计师订单如果设计师未抢单,超时(5分钟)设计订单时时给设计师派送, 设计师公众号中收到派单信息 设计发布者收到派单成功信息 环境 centos ...
- 深入理解xLua基于IL代码注入的热更新原理
目前大部分手游都会采用热更新来解决应用商店审核周期长,无法满足快节奏迭代的问题.另外热更新能够有效降低版本升级所需的资源大小,节省玩家的时间和流量,这也使其成为移动游戏的主流更新方式之一. 热更新可以 ...
- iOS 开发-- Runtime 1小时入门教程
1小时让你知道什么是Objective-C Runtime,并对它有一定的基本了解,可以在开发过程中运用自如. 三.Objective-C Runtime到底是什么东西? 简而言之,Objective ...
- 企业必会技能 tomcat
企业必会技能 tomcat tomcat 一.什么是Tomcat? Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta项目中的一个核心项 ...
- Runtime应用防止按钮连续点击 (转)
好久之前就看到过使用Runtime解决按钮的连续点击的问题,一直觉得没啥好记录的.刚好今天旁边同时碰到这个问题,看他们好捉急而且好像很难处理,于是我先自己看看… 前面自己也学习了很多Runtime的东 ...
- 自定义注解之运行时注解(RetentionPolicy.RUNTIME)
对注解概念不了解的可以先看这个:Java注解基础概念总结 前面有提到注解按生命周期来划分可分为3类: 1.RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成clas ...
随机推荐
- Foundation框架基本数据类型
NSNubmer NSNumber是一个类,该类中存在多种处理数值的方法,可直接创建该类的实例变量 // 定义3个NSNumber类型的变量 NSNumber *myNumber, *floatNum ...
- [PaPaPa][需求说明书][V1.0]
前 言 嘿嘿!嘿嘿!嘿嘿嘿嘿!大家好,我是XXX! 经过30K大大几篇文章在博客园怒刷存在感之后,咱们的小群瞬间从70人的数量增加到了将近400人.一下子加进来这么多人我还真是有点不适应啊! 我知 ...
- java之数组
数组概述: 1.数组可以看成是多个相同数据类型数据的组合,对这些数据的统一管理. 2.数组变量属引用类型,数组也可以看成是对象,数组中的每个元素相当于该对象的成员变量. 3.数组中的元素可以是任何类型 ...
- 跟随标准与Webkit源码探究DOM -- 获取元素之getElementById
按照ID获取元素 -- getElementById 标准 DOM 1,定义在HTMLDocument Interface 中,原型Element getElementById(in DOMStrin ...
- Asp.net mvc 各个组件的分离
1. 系统常见的分层 在开发asp.net mvc应用的时候,visual studio 给我们创建了默认的文档结构,一般情况下我们在一个项目下工作,参考微软的官方例子:ContosoUniversi ...
- 403 Forbidden client denied by server configuration[apache2, linux]
在LAMP的配置过程中, 由于APACHE的版本问题, 即使是APACHE2和APACHE2.2也有很大的不同. 一般都有同一个环境配置多个虚拟网站的情况, 如果你在配置过程中遇到APACHE的不同版 ...
- codeforce No to Palindromes!(枚举)
/* 题意:给定一个字符串中没有任何长度>1的回文子串!求按照字典序的该串的下一个字符串 也不包含长度>1的任何回文子串! 思路:从最低位进行枚举,保证第i位 不与 第 i-1位和第 i- ...
- C++的最佳特性(译)
最近看到了很多优秀的文章,包括<Why mobile web apps are slow>,实在忍不住翻译出来跟大家分享.这篇文章通过大量的实验和参考文献向我们说明移动应用开发所遇到的问题 ...
- 简约而不简单:网站着陆页的设计(Landing Page Design)
着陆页是一个在线营销的概念,是指当访客点击一个搜索引擎优化的搜索结果进入的第一个页面或“着陆”页面.这是一个重要的页面,它和提供的产品或服务的广告有点类似,提供了与产品相关的精确的信息,告诉客户可以购 ...
- OpenCV开发环境配置-Windows/MinGW/Clion/CMake
临时更换成了TDM-GCC,和mingw类似,这里只是声明一下. 由于opencv下载下来的.exe安装包实际上是没有mingw(gcc)匹配的/动静态库,因此这些东西需要我们自己使用mingw编译. ...