转发:博客园编程小翁

OC是运行时语言,只有在程序运行时,才会去确定对象的类型,并调用类与对象相应的方法。利用runtime机制让我们可以在程序运行时动态修改类、对象中的所有属性、方法,就算是私有方法以及私有属性都是可以动态修改的。本文旨在对runtime的部分特性小试牛刀,更多更全的方法可以参考系统API文件<objc/runtime.h>,demo例子可以参见CSDN的runtime高级编程系列文章。

我们出发吧!

先看一个非常平常的Father类:

#import <Foundation/Foundation.h>@interface Father : NSObject
@property (nonatomic, assign) int age;
@end

#import "Father.h"@interface Father ()
{NSString *_name;
}- (void)sayHello;@end@implementation Father- (id)init
{if (self = [super init]) {_name = @"wengzilin";[_name copy];self.age = 27;}return self;
}
- (void)dealloc
{[_name release];_name = nil;[super dealloc];
}
- (NSString *)description
{return [NSString stringWithFormat:@"name:%@, age:%d", _name, self.age];
}
- (void)sayHello
{NSLog(@"%@ says hello to you!", _name);
}
- (void)sayGoodbay
{NSLog(@"%@ says goodbya to you!", _name);
}

如果你没接触过runtime,那当我问你:“Father之外的类能控制的属性有哪些?能控制的方法有哪些?”时,你估计会回答:“我们可以访问age属性,不能访问_name变量;可以访问age的setter/getter方法,其他方法都不行”。这种回答是OK的,因为教科书上以及面向对象的思想告诉我们,事实如此。但是,我会说,有一种方法是APPLE允许的而且可以不受这些规则限制的途径可以做到想访问什么就访问什么、想修改什么就修改什么,那就是本文的主题:RUNTIME!

现在我们简单地将本文的主题分为两部分:(1)控制私有变量  (2)控制私有函数,因为二者所用的runtime差异较大,函数部分会复杂一些

(1)控制变量

想要控制一个类的私有变量,那第一步就要知道这个类到底有哪些隐藏的变量,以及这些隐藏的变量类型是什么。或许你会说:“这不是很显然吗?.h文件都写着呢!”。如果你真这么想就特错特错了,很多正规的写法都是尽量避免在.h文件中出现私有变量,绝大部分都会选择方法.m文件的extension中,extension就是匿名的category。我猜测这也是一种防止hack的措施吧。不管这些变量放在何处,runtime都可以让他们无所遁形!先看代码,看不懂不要紧,后面会有解释:

- (void)tryMember
{Father *father = [[Father alloc] init];NSLog(@"before runtime:%@", [father description]);unsigned int count = 0;Ivar *members = class_copyIvarList([Father class], &count);for (int i = 0 ; i < count; i++) {Ivar var = members[i];const char *memberName = ivar_getName(var);const char *memberType = ivar_getTypeEncoding(var);NSLog(@"%s----%s", memberName, memberType);}
}

显示如下:

2015-03-17 16:10:28.003 WZLCodeLibrary[38574:3149577] before runtime:name:wengzilin, age:27
2015-03-17 16:10:28.003 WZLCodeLibrary[38574:3149577] _name----@"NSString"
2015-03-17 16:10:28.003 WZLCodeLibrary[38574:3149577] _age----i

从log中我们知道了,Father类有两个变量,一个公开的包装成属性的age, 类型是int,一个花括号{}内的私有变量_name,类型是NSString。代码中标红色的部分就是runtime.h的api,

class_copyIvarList:获取类的所有属性变量,count记录变量的数量IVar是runtime声明的一个宏,是实例变量的意思,instance variable,在runtime中定义为 typedef struct objc_ivar *Ivari

var_getName:将IVar变量转化为字符串

ivar_getTypeEncoding:获取IVar的类型

如果我们现在想对_name动手,不经过Father同意偷偷修改它呢?我们继续往下做:(接着上面的代码)

    Ivar m_name = members[0];object_setIvar(father, m_name, @"zhanfen");NSLog(@"after runtime:%@", [father description]);

显示如下:

2015-03-17 16:10:28.004 WZLCodeLibrary[38574:3149577] after runtime:name:zhanfen, age:27

我们发现,_name属性被强制改过来了,有wengzilin改为现在zhanfen。

(2)控制私有函数

对于私有变量,我们能做的顶多修改变量的值,但对于私有函数,我们可以玩非常多的花样,比如:在运行时动态添加新的函数、修改私有函数、交换其中两个私有函数的实现、替换私有函数...

同样地,控制的第一步是获得Father类的所有私有方法,我们可以得到.m文件中所有有显式实现的方法以及属性变量的setter+getter方法都会被找到:

- (void)tryMemberFunc
{unsigned int count = 0;Method *memberFuncs = class_copyMethodList([Father class], &count);//所有在.m文件显式实现的方法都会被找到for (int i = 0; i < count; i++) {SEL name = method_getName(memberFuncs[i]);NSString *methodName = [NSString stringWithCString:sel_getName(name) encoding:NSUTF8StringEncoding];NSLog(@"member method:%@", methodName);}
}

显示如下:

2015-03-17 17:02:33.343 WZLCodeLibrary[38748:3170794] member method:setAge:
2015-03-17 17:02:33.343 WZLCodeLibrary[38748:3170794] member method:age
2015-03-17 17:02:33.344 WZLCodeLibrary[38748:3170794] member method:sayHello
2015-03-17 17:02:33.344 WZLCodeLibrary[38748:3170794] member method:sayGoodbay
2015-03-17 17:02:33.344 WZLCodeLibrary[38748:3170794] member method:description
2015-03-17 17:02:33.344 WZLCodeLibrary[38748:3170794] member method:dealloc
2015-03-17 17:02:33.344 WZLCodeLibrary[38748:3170794] member method:init

Method:runtime声明的一个宏,表示一个方法,typedef struct objc_method *Method;

class_copyMethodList:获取所有方法

method_getName:读取一个Method类型的变量,输出我们在上层中很熟悉的SEL

=========

接下来我们试着添加新的方法试试(这种方法等价于对Father类添加Category对方法进行扩展):

- (void)tryAddingFunction
{class_addMethod([Father class], @selector(method::), (IMP)myAddingFunction, "i@:i@");}
//具体的实现,即IMP所指向的方法
int myAddingFunction(id self, SEL _cmd, int var1, NSString *str)
{NSLog(@"I am added funciton");return 10;
}

- (void)tryMemberFunc
{//动态添加方法[self tryAddingFunction];count = 0;memberFuncs = class_copyMethodList([Father class], &count);//所有在.m文件显式实现的方法都会被找到for (int i = 0; i < count; i++) {SEL name = method_getName(memberFuncs[i]);NSString *methodName = [NSString stringWithCString:sel_getName(name) encoding:NSUTF8StringEncoding];NSLog(@"member method:%@", methodName);}//尝试调用新增的方法Father *father = [[Father alloc] init];[father method:10 :@"111"];//当你敲入father实例后,是无法获得method的提示的,只能靠手敲。而且编译器会给出"-method" not found的警告,可以忽略[father release];
}

输出结果:

2015-03-17 17:02:33.345 WZLCodeLibrary[38748:3170794] member method:method::
2015-03-17 17:02:33.345 WZLCodeLibrary[38748:3170794] member method:setAge:
2015-03-17 17:02:33.345 WZLCodeLibrary[38748:3170794] member method:age
2015-03-17 17:02:33.345 WZLCodeLibrary[38748:3170794] member method:sayHello
2015-03-17 17:02:33.345 WZLCodeLibrary[38748:3170794] member method:sayGoodbay
2015-03-17 17:02:33.345 WZLCodeLibrary[38748:3170794] member method:description
2015-03-17 17:02:33.346 WZLCodeLibrary[38748:3170794] member method:dealloc
2015-03-17 17:02:33.346 WZLCodeLibrary[38748:3170794] member method:init

我们可以看到,method::方法的确被添加进类中了。有童鞋会问,如果在其他类文件中实例化Father类,还能调用到-method方法吗?答案是可以的,我试验过,在MRC下尽管无法获得代码提示,但请坚定不移地敲入[father method:xx :xx]方法!(在ARC下会报no visible @interface 错误)

接下来,我们拿系统函数玩玩,目标是让NSString函数的大小写转换功能对调,让APPLE乱套:

- (void)tryMethodExchange
{Method method1 = class_getInstanceMethod([NSString class], @selector(lowercaseString));Method method2 = class_getInstanceMethod([NSString class], @selector(uppercaseString));method_exchangeImplementations(method1, method2);NSLog(@"lowcase of WENG zilin:%@", [@"WENG zilin" lowercaseString]);NSLog(@"uppercase of WENG zilin:%@", [@"WENG zilin" uppercaseString]);
}

输出结果:

2015-03-17 17:20:16.073 WZLCodeLibrary[38861:3180978] lowcase of WENG zilin:WENG ZILIN
2015-03-17 17:20:16.290 WZLCodeLibrary[38861:3180978] uppercase of WENG zilin:weng zilin

转载于:https://www.cnblogs.com/fantasy3588/p/5221178.html

ios runtime (2)相关推荐

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

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

  2. iOS攻防 - (十)theos的介绍,安装和使用

    iOS攻防 - (十)Theos的介绍,安装和使用 1.介绍 Theos就是一套越狱开发工具包 2.安装 2.1 下载地址 : https://github.com/iOS-Reverse-Engin ...

  3. CUDA运行时 Runtime(四)

    CUDA运行时 Runtime(四) 一. 图 图为CUDA中的工作提交提供了一种新的模型.图是一系列操作,如内核启动,由依赖项连接,依赖项与执行分开定义.这允许定义一次图形,然后重复启动.将图的定义 ...

  4. CUDA运行时Runtime(三)

    CUDA运行时Runtime(三) 一.异步并发执行 CUDA将以下操作公开为可以彼此并发操作的独立任务: 主机计算: 设备计算: 从主机到设备的内存传输: 从设备到主机的存储器传输: 在给定设备的存 ...

  5. CUDA运行时 Runtime(二)

    CUDA运行时 Runtime(二) 一. 概述 下面的代码示例是利用共享内存的矩阵乘法的实现.在这个实现中,每个线程块负责计算C的一个方子矩阵C sub,块内的每个线程负责计算Csub的一个元素.如 ...

  6. CUDA运行时 Runtime(一)

    CUDA运行时 Runtime(一) 一. 概述 运行时在cudart库中实现,该库通过静态方式链接到应用程序库cudart.lib和 libcudart.a,或动态通过cudart.dll或者lib ...

  7. iOS开发(9)UISlider

    UISlider是进度条控件 //创建UISlider UISlider *s1 = [[UISlider alloc] initWithFrame:CGRectMake(30, 100, 150, ...

  8. Objective-C Runtime (三):Method Swizzling(方法替换)

    Objective-C Runtime (三):Method Swizzling(方法替换) Method Swizzling是一种改变改变一个'selector'的实际实现的技术.通过这一技术,我们 ...

  9. 使用YOLO Core ML模型构建对象检测iOS应用(七)

    目录 在我们的应用程序中添加模型 在捕获的视频帧上运行目标检测 绘制边界框 实际应用 下一步? 总目录 将ONNX对象检测模型转换为iOS Core ML(一) 解码Core ML YOLO对象检测器 ...

最新文章

  1. SpringCloud 微服务架构,适合接私活(附源码)
  2. Python成长之路第一篇(4)_if,for,while条件语句
  3. 在PPT中通过插入重叠的图形获得新的图形
  4. java 微商城开发_Java网上商城系统可以开微信商城吗
  5. .NET Core on K8S 学习与实践系列文章索引 (更新至20191116)
  6. 开源当自强:我们不是“便宜货”
  7. c++ 访问控制与封装
  8. Application对象 简单的聊天室
  9. 2款在线FM音乐聚合播放PHP源码 带搜索
  10. python yield
  11. ASP.NET中将数据输出到Excel
  12. java读properties的通用类,兼容linux和windows
  13. 1901005每日一句
  14. 全面理解面向对象的 JavaScript
  15. 隐藏身份证中间几位工具类
  16. Android app性能优化解决卡慢顿之布局优化
  17. 树莓派系统镜像的下载和烧录
  18. android录音波浪动画_Android使用音频信息绘制动态波纹
  19. android能播放4k视频格式,安卓APP,无广告支持多种格式的万能视频播放器
  20. 天大计算机英语面试,天大考研复试英文自我介绍

热门文章

  1. 大企业中,Java面试官最爱问的问题集锦
  2. C#一个完整的电子邮件操作类
  3. JavaScript模块化开发(一)基础知识
  4. nginx做负载CDN加速获取端真实ip
  5. android NDK 开发
  6. 在Java中获取系统属性
  7. 【重点】剑指offer——面试题25:二叉树中和为某一值的路径
  8. 关于sinX与y的大小比较取值范围计算
  9. Mac与Windows或Linux的键鼠共享神器Synergy
  10. 一.对ThreadLocal的理解