有人说现在的程序员都被惯坏了,尤其使用一些面向对象的语言开发的时候,只是简单的调用一些系统封装好的接口或者是调用一些“便利的”第三方,对于一个程序的真正实现有了解吗???又有多少了解呢???就单单的拿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 的归档反归档适用于归档对象属性较多的情况,可以减少代码量,逻辑更清晰。这种方式一般来说用的比较多,除此之外一些基本的使用方法也是比较常用的,比如说:
1、 动态的为某个类添加属性\方法, 修改属性值\方法
2 、遍历一个类的所有成员变量(属性)\所有方法  那么就这两种方式给出具体的代码实现 :
 
首先是   动态的为某个类添加属性\方法, 修改属性值\方法
 
//使用运行时需要导入头文件  #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 -----那些被忽略的技能的更多相关文章

  1. 你get了无数技能,为什么一事无成

      前几日看到阮一峰老师的发的一句话,颇有感慨,「你只是坐在电脑前,往网上发表了一段文字或者一张图片,随便什么,就能够接触到多少陌生的灵魂.这就是我热爱互联网的原因」.我打心底认为这是一个最好的时代, ...

  2. 你 get 了无数技能,为什么一事无成

    前 几日看到阮一峰老师的发的一句话,颇有感慨,「你只是坐在电脑前,往网上发表了一段文字或者一张图片,随便什么,就能够接触到多少陌生的灵魂.这就是我热 爱互联网的原因」.我打心底认为这是一个最好的时代, ...

  3. 专访笨叔叔:2019年可能是Linux年?(转)

    链接:https://zhuanlan.zhihu.com/p/57815479 2017年9月<奔跑吧 Linux内核>一书出版后得到了广大Linux从业人员和爱好者(特别是从事Linu ...

  4. 基于swoole+Redis的消息实时推送通知

    swoole+Redis将实时数据的推送 一 实现功能 设计师订单如果设计师未抢单,超时(5分钟)设计订单时时给设计师派送, 设计师公众号中收到派单信息 设计发布者收到派单成功信息 环境 centos ...

  5. 深入理解xLua基于IL代码注入的热更新原理

    目前大部分手游都会采用热更新来解决应用商店审核周期长,无法满足快节奏迭代的问题.另外热更新能够有效降低版本升级所需的资源大小,节省玩家的时间和流量,这也使其成为移动游戏的主流更新方式之一. 热更新可以 ...

  6. iOS 开发-- Runtime 1小时入门教程

    1小时让你知道什么是Objective-C Runtime,并对它有一定的基本了解,可以在开发过程中运用自如. 三.Objective-C Runtime到底是什么东西? 简而言之,Objective ...

  7. 企业必会技能 tomcat

    企业必会技能 tomcat tomcat   一.什么是Tomcat? Tomcat是Apache 软件基金会(Apache Software Foundation)的Jakarta项目中的一个核心项 ...

  8. Runtime应用防止按钮连续点击 (转)

    好久之前就看到过使用Runtime解决按钮的连续点击的问题,一直觉得没啥好记录的.刚好今天旁边同时碰到这个问题,看他们好捉急而且好像很难处理,于是我先自己看看… 前面自己也学习了很多Runtime的东 ...

  9. 自定义注解之运行时注解(RetentionPolicy.RUNTIME)

    对注解概念不了解的可以先看这个:Java注解基础概念总结 前面有提到注解按生命周期来划分可分为3类: 1.RetentionPolicy.SOURCE:注解只保留在源文件,当Java文件编译成clas ...

随机推荐

  1. MariaDB Galera Cluster 10.1 只支持 LINUX ?!

    MariaDB Galera Cluster  (MariaDB 10.1) 当前只支持:LINUX ! 参考: https://mariadb.com/kb/en/mariadb/getting-s ...

  2. STL容器删除元素的陷阱

    今天看Scott Meyers大师的stl的用法,看到了我前段时间犯的一个错误,发现我写的代码和他提到错误代码几乎一模一样,有关stl容器删除元素的问题,错误的代码如下:std::vector< ...

  3. Red Hat Enterprise Linux 各版本详细说明

    https://access.redhat.com/articles/3078#RHEL7 Red Hat Enterprise Linux Release Dates Updated Novembe ...

  4. osgi:设置httpservice端口号

    使用osgi开发http类的Service,在启动时默认端口是80.但有可能这个端口已经被本机上的其他程序占用.那么解决问题的方法有两种:1)关闭或修改占用程序的端口: 2)修改osgi启动时的端口. ...

  5. ubuntu 12.04亮度无法调节和无法保存屏幕亮度解决办法(echo_brightness)

    经过多次更改失败重装后终于在官网的answers找到了解决办法:原文链接 http://askubuntu.com/questions/3841/desktop-doesnt-remember-bri ...

  6. node.js 的 os 模块

    Node.js的os module 提供了一系列跟操作系统相关的操作函数,比较简单,所以功能也就十分有限.我们可以去官网看各个函数的介绍: http://nodejs.org/api/os.html ...

  7. Office2016下载地址

    Office 2016 专业增强版32 位: 文件名:SW_DVD5_Office_Professional_Plus_2016_W32_ChnSimp_MLF_X20-41351.ISO SHA1: ...

  8. [持续更新]UnsatisfiedLinkError常见问题及解决方案

    想必很多开发者和我们一样,遇到过许多UnsatisfiedLinkError的困难,着实令人头疼,现在总结一下,希望能帮助更多的人. 常见错误 lib库不同目录下的SO文件参差不齐. lib库目录下的 ...

  9. 哇塞,原来自己写 Google Chrome 浏览器扩展(插件)这么容易!

    1. 首先新建一个记事本,命名为 manifest.json,这是写 Google Chrome 浏览器扩展必须的文件 { "manifest_version": 2, " ...

  10. Apache+tomcat+mod_jk+centos6.2负载均衡集群配置--转载

    转载地址:http://blog.163.com/chenhui_java/blog/static/17267249420128101191860/ 注: 由于长期受转载毒害,所以本人日志均是原创:其 ...