有人说现在的程序员都被惯坏了,尤其使用一些面向对象的语言开发的时候,只是简单的调用一些系统封装好的接口或者是调用一些“便利的”第三方,对于一个程序的真正实现有了解吗???又有多少了解呢???就单单的拿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. 解析Javascript中大括号“{}”的多义性

    JS中大括号有四种语义作用 语义1,组织复合语句,这是最常见的 复制代码 代码如下: if( condition ) {   //... }else {   //... } for() {   //. ...

  2. Qt 添加资源文件

    *本人乃小白,博文主要用于个人记录,不保证内容准确无误* 我们编写的gui可能需要一些额外的资源(比如贴图用的图片),可用资源文件统一管理.以下以图片为例. 用qt creator 打开工程,为工程新 ...

  3. [原]SQLite的学习系列之获取数据库版本二

    本系列文章主要是使用C++语言来调用其API,达到管中窥豹的目的.另外本文使用的开发环境为mac + clion,并且基于SQLite 3.7.14来进行开发. 一.去下载sqlite-amalgam ...

  4. 文本框不够长,显示“XXX...”

    WPF: How to make the TextBox/TextBlock/Label show "xxx..." if the text content too long? 设 ...

  5. VIM配置相关记录

    把一直使用中的vim配置做个GIT入库管理,也把之前积累在机器上的文档,做个汇总. https://github.com/wujuguang/kyvim 1. 安装完整版vim vi和vim的区别?在 ...

  6. NopCommerce之事件通知

    mark下,等下写了. NewsController 控制器NewsCommentAdd()缓存清除,使用到了事件

  7. [IR] Compression

    关系:Vocabulary vs. collection size Heaps’ law: M = kTbM is the size of the vocabulary, T is the numbe ...

  8. 连接不上mysqlworkbench问题解决方法

    连接mysqlworkbench出现如下提示:     查看ip     加入host的范围 mysql> select user,host from mysql.user;+--------- ...

  9. Spring基础——在Spring Config 文件中配置 Bean

    一.基于 XML 的 Bean 的配置——通过全类名(反射) <bean <!-- id: bean 的名称在IOC容器内必须是唯一的若没有指定,则自动的将全限定类名作为 改 bean 的 ...

  10. 第二次sprint团队贡献分

    201406114105       董婷婷           22 201406114157       容杰龙           21 201406114343       卓炜杰       ...