一、初识runtime

Objective-C是一种动态语言,所谓动态语言,是在程序执行时动态的确定变量类型,执行变量类型对应的方法的。因此,在Object-C中常用字符串映射类的技巧来动态创建类对象。因为OC的动态语言特性,我们可以通过一些手段,在程序运行时动态的更改对象的变量甚至方法,这就是我们所说的runtime机制。

二、你还有什么办法操作这样的变量么?

首先,我们先来看一个例子,这里有我创建的一个MyObject类:

//.h===========================

@interface MyObject : NSObject

{

@private

int privateOne;

NSString * privateTow;;

}

@end

//=============================

//.m===========================

@interface MyObject()

{

@private

NSString * privateThree;

}

@end

@implementation MyObject

- (instancetype)init

{

self = [super init];

if (self) {

privateOne=1;

privateTow=@"Tow";

privateThree=@"Three";

}

return self;

}

-(NSString *)description{

return [NSString stringWithFormat:@"one=%d\ntow=%@\nthree=%@\n",privateOne,privateTow,privateThree];

}

@end

//=============================

这个类是相当的安全,首先,在头文件中没有提供任何的方法接口,我们没有办法使用点语法做任何操作,privateOne和PrivateTow两个变量虽然声明在了头文件中,却是私有类型的,通过指针的方式我们虽然可以看到他们,却不能做任何读取修改的操作,xcode中的提示如下:

他会告诉我们,这是一个私有的变量,我们不能使用。对于privateThree,我们更是束手无策,不仅不能使用,我们甚至都看不到它的存在。那么对于这种情况,你有什么办法操作这些变量么?对,是时候展现真正的技术了:runtime!

三、通过runtime获取对象的变量列表

要操作对象的变量,我们首先应该要捕获这些变量,让他们无处遁形。无论声明在头文件或是实现文件,无论类型是公开的还是私有的,只要声明了这个变量,系统就会为其分配空间,我们就可以通过runtime机制捕获到它,代码如下:

#import "ViewController.h"

#import "MyObject.h"

//包含runtime头文件

#import

@interface ViewController ()

@end

@implementation ViewController

- (void)viewDidLoad {

[super viewDidLoad];

//我们先声明一个unsigned int型的指针,并为其分配内存

unsigned int * count = malloc(sizeof(unsigned int));

//调用runtime的方法

//Ivar:方法返回的对象内容对象,这里将返回一个Ivar类型的指针

//class_copyIvarList方法可以捕获到类的所有变量,将变量的数量存在一个unsigned int的指针中

Ivar * mem = class_copyIvarList([MyObject class], count);

//进行遍历

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

//通过移动指针进行遍历

Ivar var = * (mem+i);

//获取变量的名称

const char * name = ivar_getName(var);

//获取变量的类型

const char * type = ivar_getTypeEncoding(var);

NSLog(@"%s:%s\n",name,type);

}

//释放内存

free(count);

//注意处理野指针

count=nil;

}

- (void)didReceiveMemoryWarning {

[super didReceiveMemoryWarning];

// Dispose of any resources that can be recreated.

}

@end

打印结果如下,其中i表示int型:

是不是小吃惊了一下,无论变量在哪里,只要它在,就让它无处遁形。

四、让我找到你,就让我改变你!

仅仅能够获得变量的类型和名字或许并没有什么卵用,没错,我们获取变量的目的不是为了观赏,而是为了操作它,这对runtime来说,也是小事一碟。代码如下:

- (void)viewDidLoad {

[super viewDidLoad];

//获取变量

unsigned int  count;

Ivar * mem = class_copyIvarList([MyObject class],&count);

//创建对象

MyObject * obj = [[MyObject alloc]init];

NSLog(@"before runtime operate:%@",obj);

//进行变量的设置

object_setIvar(obj, mem[0],10);

object_setIvar(obj, mem[1], @"isTow");

object_setIvar(obj, mem[2], @"isThree");

NSLog(@"after runtime operate:%@",obj);

}

Tip:在修改int型变量的时候,你或许会遇到一个问题,ARC下,编译器不允许你将int类型的值赋值给id,在buildset中将Objective-C Automatic Reference Counting修改为No即可。

打印效果如下:

可以看到,那些看似非常安全的变量被我们修改了。

五、让我看看你的方法吧

变量通过runtime机制我们可以取到和改变值,那么我们再大胆一点,试试那些私有的方法,首先我们在MyObject类中添加一些方法,我们只实现,并不声明他们:

@interface MyObject()

{

@private

NSString * privateThree;

}

@end

@implementation MyObject

- (instancetype)init

{

self = [super init];

if (self) {

privateOne=1;

privateTow=@"Tow";

privateThree=@"Three";

}

return self;

}

-(NSString *)description{

return [NSString stringWithFormat:@"one=%d\ntow=%@\nthree=%@\n",privateOne,privateTow,privateThree];

}

-(NSString *)method1{

return @"method1";

}

-(NSString *)method2{

return @"method2";

}

这样的方法我们在外面是无法调用他们的,和操作变量的思路一样,我们先要捕获这些方法:

//获取所有成员方法

Method * mem = class_copyMethodList([MyObject class], &count);

//遍历

for(int i=0;i

SEL name = method_getName(mem[i]);

NSString * method = [NSString stringWithCString:sel_getName(name) encoding:NSUTF8StringEncoding];

NSLog(@"%@\n",method);

}

打印如下:

得到了这些方法名,我们大胆的调用即可:

MyObject * obj = [[MyObject alloc]init];

NSLog(@"%@",[obj method1]);

Tip:这里编译器不会给我们方法提示,放心大胆的调用即可。

六、动态的为类添加方法

这个runtime机制最强大的部分要到了,试想,如果我们可以动态的向类中添加方法,那将是一件多么令人激动的事情,注意,这里是动态的添加,和类别的最大不同在于这种方式是运行时才决定是否添加方法的。

- (void)viewDidLoad {

[super viewDidLoad];

//添加一个新的方法,第三个参数是返回值的类型v是void,i是int,:是SEL,对象是@等

class_addMethod([MyObject class], @selector(method3), (IMP)logHAHA, "v");

unsigned int count = 0;

Method * mem = class_copyMethodList([MyObject class], &count);

for(int i=0;i

SEL name = method_getName(mem[i]);

NSString * method = [NSString stringWithCString:sel_getName(name) encoding:NSUTF8StringEncoding];

NSLog(@"%@\n",method);

}

MyObject * obj = [[MyObject alloc]init];

//运行这个方法

[obj performSelector:@selector(method3)];

}

//方法的实现

void logHAHA(){

NSLog(@"HAHA");

}

运行结果如下:

从前五行可以看出,方法已经加进去了,从最后一行可以看出,执行没有问题。

七、做点小手脚

程序员总是得寸进尺的,现在,我们要做点事情,用我们的函数替换掉类中的函数:

- (void)viewDidLoad {

[super viewDidLoad];

MyObject * obj = [[MyObject alloc]init];

//替换之前的方法

NSLog(@"%@", [obj method1]);

//替换

class_replaceMethod([MyObject class], @selector(method1), (IMP)logHAHA, "v");

[obj method1];

}

void logHAHA(){

NSLog(@"HAHA");

}

打印如下:

这次够cool吧,通过这个方法,我们可以把系统的函数都搞乱套。当然,runtime还有许多很cool的方法:

id object_copy(id obj, size_t size)

拷贝一个对象

id object_dispose(id obj)

释放一个对象

const char *object_getClassName(id obj)

获取对象的类名

ive

void method_exchangeImplementations(Method m1, Method m2)

交换两个方法的实现

linux 软件 runtime,Objective-C中runtime机制的应用相关推荐

  1. java的runtime类,java中Runtime类的简单应用

    1.简介 JVM中,Runtime类是唯一与JVM的运行状态相关的类,并且默认情况下提供此类的实例化对象. 由于每个JVM进程中只允许运行时类的一个对象,因此默认情况下该类的构造方法是私有化的,这表明 ...

  2. linux软件安装 home,Ubuntu中安装建筑设计软件Sweet Home 3D

    原标题:Ubuntu中安装建筑设计软件Sweet Home 3D 本教程介绍如何在Ubuntu 16.04,Ubuntu 18.04,Ubuntu 19.04及更高版本中轻松安装最新的Sweet Ho ...

  3. 编程环境中Runtime(运行时)的三个含义

    编程环境中Runtime(运行时)的三个含义 转自:https://www.zhihu.com/question/20607178 知乎答主@doodlewind 三个含义 实际上编程语境中的 run ...

  4. 刨根问底Objective-C Runtime

    该笔记分为四篇: 刨根问底Objective-C Runtime(1)- Self & Super 刨根问底Objective-C Runtime(2)- Object & Class ...

  5. OC中runtime的使用

    一.runtime简介 * RunTime简称运行时.OC就是"运行时机制",也就是在运行时候的一些机制,其中最主要的是消息机制. * 对于C语言,"函数的调用在编译的时 ...

  6. 刨根问底Objective-C Runtime(2)- Object Class Meta Class

    刨根问底Objective-C Runtime(2)- Object & Class & Meta Class Chun Tips 专注iOS开发 刨根问底Objective-C Ru ...

  7. iOS运行时-使用Runtime向Category中添加属性以及运行时介绍

    前言 了解OC的都应该知道,在一般情况下,我们是不能向Category中添加属性的,只能添加方法,但有些情况向,我们确实需要向Category中添加属性,而且很多系统的API也有一些在Category ...

  8. Runtime 在IOS中的详细使用

    ### 一.runtime简介 * RunTime简称运行时.OC就是`运行时机制`,也就是在运行时候的一些机制,其中最主要的是消息机制. * 对于C语言,`函数的调用在编译的时候会决定调用哪个函数` ...

  9. iOS中Runtime简析

    一.runtime简介 RunTime简称运行时.OC就是运行时机制,也就是在运行时候的一些机制,其中最主要的是消息机制. 对于C语言,函数的调用在编译的时候会决定调用哪个函数. 对于OC的函数,属于 ...

最新文章

  1. 关于函数调用、静态变量、预编译的习题
  2. CMake 与 Finder
  3. jMeter HTTP Request Defaults 的学习笔记
  4. Angular jasmine单元测试框架里describe的实现原理
  5. DP-访问者模式(Visitor Pattern)
  6. 布式事务实践 解决数据一致性 Spring事务机制
  7. linux下异步IO的简单例子
  8. 通过线程监控socket服务器是否done机
  9. Hadoop 面试题之七
  10. Linq to SQL 语法查询....子查询 in操作 join
  11. 和shopee哪个好_shopify和虾皮shopee哪个好?虾皮shopee电商哪个平台好
  12. 【QT编程】QT介绍——What‘s QT?
  13. 人人开源(后台代码、前端项目、代码自动生成)
  14. 脚本工具之下载M3U8文件类型的完整视频
  15. android第三方库进程,Android 第三方库AgentWeb的使用
  16. 《华为工作法》6 华为的成功不是一个人的
  17. 物联网产品的发展简介(二)【产品篇02】
  18. 如何将诸如Acrobat Reader DC等默认安装在C盘的软件,安装在非系统盘?
  19. Threadlocal学习及内存泄漏原因和解决方案
  20. 薅羊毛 | Python 自动化带你轻松赚钱(完结版)

热门文章

  1. [AHOI2004]数字迷阵 结论+矩乘
  2. 2018怎么更换图框_2018 乐博睿 全年回顾
  3. 【Level 08】U06 Good Feeling L6 A 3D experience
  4. 【英语学习】【English L06】U07 Jobs L2 I have my own bakery now
  5. 【英语学习】【Daily English】U07 Restaurant L02 I don't think this is what I ordered?
  6. Intel Haswell/Broadwell架构/微架构/流水线 (2)-流水线前端
  7. Intel Core Enhanced Core架构/微架构/流水线 (1) - 特性概述
  8. open一个绝对路径地址 python_实例15:用Python批量转换doc文件为docx文件
  9. 域名抢注php程序_“丁真”被抢注,蹭热点这门生意,能成就好品牌?
  10. java rmi 安全管理器_Java:没有安全管理器:RMI类加载器被禁用