ios-Runtime调用私有方法
有时在代码中会有需要调用私有方法的场景,如不想import太多头文件;想组件设计一些解耦的模块;查看别人模块中未暴露的代码进行分析等。
在 ios 中调用私有方法有很多种方式,主要是通过Runtime去实现。下面自己也测试一下。
新建一个Person类,Person.h中不写代码,Person.m中如下:
#import "Person.h" @implementation Person - (void)eat
{
NSLog(@"xxx eat====");
} - (void)eat:(NSString *)str str2:(NSString *)str2 str3:(NSString *)str3
{
NSLog(@"xxx eat====%@==%@==%@", str, str2, str3);
} @end
【找到该类methodLists里的方法】
要想调用私有方法,首先要知道类有什么哪些方法。可以通过如下代码得到方法的一些信息:(不管私有还是公有,只要在该类的methodLists里)
// 获取实例方法
- (void)getMethods
{
int outCount = ;
Person *p = [Person new];
Method *methods = class_copyMethodList([p class], &outCount);
for (int i = ; i < outCount; i ++) {
NSLog(@"=============%d", i);
// 获取方法名
Method method = methods[i];
SEL methodName = method_getName(method);
NSLog(@"方法名= %@", NSStringFromSelector(methodName)); // 获取参数
char argInfo[] = {};
unsigned int argCount = method_getNumberOfArguments(method);
for (int j = ; j < argCount; j ++) {
// 参数类型
method_getArgumentType(method, j, argInfo, );
NSLog(@"参数类型= %s", argInfo);
memset(argInfo, '\0', strlen(argInfo));
} // 获取方法返回值类型
char retType[] = {};
method_getReturnType(method, retType, );
NSLog(@"返回类型值类型= %s", retType);
}
free(methods);
}
上面代码使用runtime获取一些方法的信息:方法名,参数对应的类型,返回值类型。上面这个方法打印结果如下:
=============
方法名= eat
参数类型= @
参数类型= :
返回类型值类型= v
=============
方法名= eat:str2:str3:
参数类型= @
参数类型= :
参数类型= @
参数类型= @
参数类型= @
返回类型值类型= v
打印的类型是一些符号,不知道这是什么鬼,但其实这是苹果的类型编码。它对照的含义如下:
v A void —— (为空)
@ An object (whether statically typed or typed id) —— (id类型)
: A method selector (SEL) —— (方法名)
上面打印的方法信息中 eat 方法也有两个参数,实际每个方法都有两个隐藏参数。(_cmd是当前方法编号)
【调用私有方法】
调用私有方法有多种方式,但其实最终都大同小异。如下:
1. 使用 performSelector 下面2和3行结果一样。这样比使用对象直接调用好处是编译器不会报错,也不用方法暴露头文件。
Person *p = [Person new];
[p performSelector:@selector(eat)]; // log: xxx eat====
[p performSelector:NSSelectorFromString(@"eat")]; // log: xxx eat====
2. 使用 objc_msgSend ,对比上面 objc_msgSend 好处是传递多个参数时更为方便。objc_msgSend深入学习
Person *p = [Person new]; // 需要引用 Person.h 头文件
objc_msgSend(p, @selector(eat:str2:str3:), @"", @"", @""); // log: eat====1==2==3
3. 利用函数实现IMP,IMP类型结构与objc_msgSend底层是同一类型,与2中实现无差别
Person *p = [Person new];
IMP imp = [p methodForSelector:@selector(eat)];
void (* tempFunc)(id target, SEL) = (void *)imp;
tempFunc(p, @selector(eat)); // log: xxx eat====
4. 使用类对象发送消息,上面3种方式都需要引用 Person.h 头文件,这里类对象进行调用可以解决这个问题。
Class pClassObj = NSClassFromString(@"Person");
objc_msgSend([pClassObj new], @selector(eat));
【类对象】
进入 objc.h 中查看 Class 与 Object 结构定义。每个 objc_object 下都有一个 isa 指针指向这个对象所属的 objc_class。
/// An opaque type that represents an Objective-C class.
typedef struct objc_class *Class; /// Represents an instance of a class.
struct objc_object {
Class _Nonnull isa OBJC_ISA_AVAILABILITY;
};
再看一下 objc_class 定义的结构。它里面只有一个 isa 指针,下面那些属性在 objc2 中已经不可用了。
struct objc_class {
Class _Nonnull isa OBJC_ISA_AVAILABILITY; #if !__OBJC2__
Class _Nullable super_class OBJC2_UNAVAILABLE;
const char * _Nonnull name OBJC2_UNAVAILABLE;
long version OBJC2_UNAVAILABLE;
long info OBJC2_UNAVAILABLE;
long instance_size OBJC2_UNAVAILABLE;
struct objc_ivar_list * _Nullable ivars OBJC2_UNAVAILABLE;
struct objc_method_list * _Nullable * _Nullable methodLists OBJC2_UNAVAILABLE;
struct objc_cache * _Nonnull cache OBJC2_UNAVAILABLE;
struct objc_protocol_list * _Nullable protocols OBJC2_UNAVAILABLE;
#endif } OBJC2_UNAVAILABLE;
它里面的 isa 指向的是 MetaClass (元类)。Class 和 MetaClass :
- 当我们对一个实例发送消息时(-开头的方法),会在该 instance 对应的类的 methodLists 里查找。
- 当我们对一个类发送消息时(+开头的方法),会在该类的 MetaClass 的 methodLists 里查找。
- 每个 Class 都有一个 isa 指针指向一个唯一的 Meta Class
- 每一个 Meta Class 的 isa 指针都指向最上层的 Meta Class,即 NSObject 的 MetaClass,而最上层的 MetaClass 的 isa 指针又指向自己
获取类对象
[NSObject class];
获取元类对象
Class class = [NSObject class];
Class metaClass = objc_getClass(class);
【实例对象成员变量】
上面可以知道,实例对象的方法存放在它对应类对象 (class) 的 methodsList 中,类方法存放它对应的元类 (metaClass) 的 methodsList 中。
一个 new 出来的对象除了它的方法,它还有成员变量。
- 成员变量是存放在实例对象之中
假如有一个 Person 对象,这个实例对象结构体中存放信息应该是这样,即成员变量存放在结构体,方法信息通过 isa 去找相应的类对象。
struct Student_IMPL {
Class isa;
int _age;
int _height;
};
ios-Runtime调用私有方法的更多相关文章
- 反射工具类.提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class,被AOP过的真实类等工具函数.java
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.ap ...
- java反射调用私有方法和修改私有属性
//调用私有方法package com.java.test; public class PrivateMethod { private String sayHello(String name) { r ...
- php通过反射方法调用私有方法
PHP 5 具有完整的反射 API,添加了对类.接口.函数.方法和扩展进行反向工程的能力. 下面我们演示一下如何通过反射,来调用执行一个类中的私有方法: <?php //MyClass这个类中包 ...
- 利用JAVA反射机制实现调用私有方法
1.fragment是AccessibilityFragment的對象.须要被調用的方法的類. setAccessible(true)并非将方法的訪问权限改成了public.而是取消java的权限控制 ...
- ios runtime部分事例方法说明
一.场景--动态改变变量 unsigned ; Ivar *ivar = class_copyIvarList([self.person class], &count); ; i<cou ...
- Java反射机制调用私有方法
1.获取目标类: 每个类都有一个class属性,通过实体类的class属性获取: Class clazz = Person.class 通过对象获取. Person p1 = new Person( ...
- 从vs2010的UnitTestFramework类库提取私有方法反射调用的方法
背景 年龄大点的程序员都知道在vs2010中创建单元测试非常的简单,鼠标定位在方法名字,右键创建单元测试,就会创建一个测试方法,即使是在私有方法上也可以创建测试方法. VS2010以后就没这么简单了, ...
- 【转】【Java】利用反射技术,实现对类的私有方法、变量访问
java关于反射机制的包主要在java.lang.reflect中,structs,hibernate,spring等框架都是基于java的反射机制. 下面是一个关于利用java的反射机制,实现了对私 ...
- Javascript 面向对象(共有方法,私有方法,特权方法,静态属性和方法,静态类)示例讲解
一,私有属性和方法 私有方法:私有方法本身是可以访问类内部的所有属性(即私有属性和公有属性),但是私有方法是不可以在类的外部被调用. <script> /* * 私有方法:私有方法本身是可 ...
随机推荐
- S5PV210 点亮Led
GPC1CON, R/W, Address = 0xE020_0080 GPC1DAT, R/W, Address = 0xE020_0084 举例 #define GPC1CON *((volati ...
- Golang之初探
什么是Go语言 Go语言介绍 产生背景: 超级复杂的C++11特性的吹捧报告的鄙视以及最终的目标是具备动态语言的开发速度的同时并要有C/C++编译语言的性能与安全性以及设计网络和多核时代的C语言 Go ...
- set 集合的函数调用
方法 意义 S.add(e) 在集合中添加一个新的元素e:如果元素已经存在,则不添加 S.remove(e) 从集合中删除一个元素,如果元素不存在于集合中,则会产生一个KeyError错误 S.dis ...
- 算法9-----输出全排列(递归)---移除K个数,剩下最小数。
1.题目:给定一个字符串,输出所有的字典序. 如: 输入字符串:'ac',输出:['ac','ca'] 输入字符串:‘abc' ,输出:['abc','acb','bac','bca','cab',' ...
- python+Appium自动化:toast定位
Toast简介 Toast是一种简易的消息提示框. 当视图显示给用户,在应用程序中显示为浮动.和Dialog不一样的是,它永远不会获得焦点,无法被点击. 用户将可能是在中间键入别的东西.Toast类的 ...
- 巧用 Img / JavaScript 采集页面数据
摘要: 当我们有一个新内容时(例如新功能.新活动.新游戏.新文章),作为运营人员总是迫不及待地希望能尽快传达到用户,因为这是获取用户的第一步.也是最重要的一步. 点此查看原文:http://click ...
- 使用memocache
直接cmd下运行 pip3 install python-memcached serializer.py 里的特别应用 如果一个表模型一些字段用到了跨表.可以这样取值 跨表字段 coach_nickn ...
- Mac OS 系统开发环境的一些坑
最近换 Mac OS 系统开发,运行项目时遇到各种报错,记录下: 1.拉取项目后,需要安装依赖 npm install ,提示需要安装 xcode,报错如下. 从官网下载 xcode 时提示要更新最新 ...
- 给程序添加git commit信息
遇到了一个客户程序出问题,自己这边始终无法重现的bug.为了检查问题,查到了一个添加git的commit信息到程序中的方法,感觉对程序版本控制十分好用. 一,项目中添加如下文件 文件结构: GitVe ...
- Java进阶知识17 Spring Bean对象的创建细节和创建方式
本文知识点(目录): 1.创建细节 1) 对象创建: 单例/多例 2) 什么时候创建? 3)是否延迟创建(懒加载) 4) 创建对象之后, ...