Runtime 又叫运行时,是一套底层的 C 语言 API,其为 iOS 内部的核心之一,我们平时编写的 OC 代码,底层都是基于它来实现的。比如:
id objc = [NSObject alloc]
objc = [objc init]
类方法本质:类对象调用[NSObject class]
id:谁发送消息
SEL: 发送什么消息
苹果运行使用objc_msgSend,如没有提示则到build setting搜索msg改为no
底层运行时会转化成发送消息
id objc = objc_msgSend(objc_getClass("NSObject"),sel_registerName("alloc"));
objc = objc_msgSend(objc,sel_registerName("init"));
最终生成消息机制,编译器做的事
最终代码,需要把当前代码重新编译,用code编译器,clang
clang -rewrite-objc 文件名
开发中runtime的使用场景:1.不得不用runtime消息机制,可以帮我们调用私有方法。2.runtime一般都是针对系统的类
方法调用流程
怎么去调用方法,对象方法:类对象的方法列表,类方法:元类中方法列表
1.通过isa指针去对应的类中查找
2.注册方法编号
3.根据方法编号去查找对应的方法
4.找到的只是最终函数实现地址,根据地址去方法去调用方法
内容五大区:栈、堆、静态区、常量区、方法区
1.栈:不需要手动管理内存,自动管理
2.堆:需要手动管理内存,自己去释放
method函数的解析
SEL selector 的简写,俗称方法选择器,实质存储的是方法的名称
IMP implement 的简写,俗称方法实现,看源码得知它就是一个函数指针
Method 对上述两者的一个包装结构.
//判断类中是否包含某个方法的实现
BOOL class_respondsToSelector(Class cls, SEL sel)
//获取类中的方法列表
Method *class_copyMethodList(Class cls, unsigned int *outCount)
//为类添加新的方法,如果方法该方法已存在则返回NO
BOOL class_addMethod(Class cls, SEL name, IMP imp, const char *types)
//替换类中已有方法的实现,如果该方法不存在添加该方法
IMP class_replaceMethod(Class cls, SEL name, IMP imp, const char *types)
//获取类中的某个实例方法(减号方法)
Method class_getInstanceMethod(Class cls, SEL name)
//获取类中的某个类方法(加号方法)
Method class_getClassMethod(Class cls, SEL name)
//获取类中的方法实现
IMP class_getMethodImplementation(Class cls, SEL name)
//获取类中的方法的实现,该方法的返回值类型为struct
IMP class_getMethodImplementation_stret(Class cls, SEL name)
//获取Method中的SEL
SEL method_getName(Method m)
//获取Method中的IMP
IMP method_getImplementation(Method m)
//获取方法的Type字符串(包含参数类型和返回值类型)
const char *method_getTypeEncoding(Method m)
//获取参数个数
unsigned int method_getNumberOfArguments(Method m)
//获取返回值类型字符串
char *method_copyReturnType(Method m)
//获取方法中第n个参数的Type
char *method_copyArgumentType(Method m, unsigned int index)
//获取Method的描述
struct objc_method_description *method_getDescription(Method m)
//设置Method的IMP
IMP method_setImplementation(Method m, IMP imp)
//替换Method
void method_exchangeImplementations(Method m1, Method m2)
//获取SEL的名称
const char *sel_getName(SEL sel)
//注册一个SEL
SEL sel_registerName(const char *str)
//判断两个SEL对象是否相同
BOOL sel_isEqual(SEL lhs, SEL rhs)
//通过块创建函数指针,block的形式为^ReturnType(id self,参数,...)
IMP imp_implementationWithBlock(id block)
//获取IMP中的block
id imp_getBlock(IMP anImp)
//移出IMP中的block
BOOL imp_removeBlock(IMP anImp)
//调用target对象的sel方法
id objc_msgSend(id target, SEL sel, 参数列表...)
动态添加方法class_addMethod
//resolveInstanceMethod对应的对象方法,resolveClassMethod对应的是类方法
//什么时候调用:只要一个对象调用了一个来实现的方法就就调用这个方法,进行处理
//作用:动态添加方法,处理为实现的方法
//class :给那个类添加方法
//SEL:添加那个方法
//IMP:implementation方法实现->函数->函数入口->函数名
//type:方法类型
+ (BOOL)resolveInstanceMethod:(SEL)sel {
if (sel == NSSelecterFromString(@"run:"))
class_addMethod(self, sel, (IMP)aaa,"v@:@");
return YES;
}
//任何方法默认都有两个隐式参数,self,_cmd
void aaa(id self,SEL _cmd,NSNumber *num) {
NSLog(@"跑了%@米",num);
}
TypeEncoding表
TypeEncoding
动态添加属性
@interface NSObject (JHObject)
//@property分类:只会生成set,get方法声明,不会生成实现,也不会生成下划线成员属性
@property NSString *name;
@end
@implementation NSObject (JHObject)
-(void)setName:(NSString *)name{
//object:给那个对象添加属性
// key 属性名称
// value 属性值
// policy 保存策略
// objc_setAssociatedObject(<#id _Nonnull object#>, <#const void * _Nonnull key#>, <#id _Nullable value#>, <#objc_AssociationPolicy policy#>)
objc_setAssociatedObject(self, "name", name, OBJC_ASSOCIATION_COPY);
}
-(NSString *)name{
return objc_getAssociatedObject(self, "name");
}
@end
交换方法
使用场景:当我们需要在系统方法里做事情时
示例:修改系统默认字体
//把类加载进内存的时候调用,只会调用一次
+(void)load {
// 系统方法
Method fun1 = class_getClassMethod(self, @selector(systemFontOfSize:));
// 自定义UIFont字体类型的方法
Method fun2 = class_getClassMethod(self, @selector(jh_systemFontOfSize:));
// 交换方法1和方法2
method_exchangeImplementations(fun1, fun2);
}
+ (UIFont *)jh_systemFontOfSize:(CGFloat)size{
UIFont *font = [UIFont fontWithName:@"Helvetica-Bold" size:size];
return font;
}
备注:
如果有不足或者错误的地方还望各位读者批评指正,可以评论留言,笔者收到后第一时间回复。
QQ/微信:976971956/ljh976971956。
简书号:超级卡布达
感谢各位观众老爷的阅读,如果觉得笔者写的还凑合,可以关注或收藏一下,不定期分享一些好玩的实用的demo给大家。
文/超级卡布达(简书作者)
著作权归作者所有,转载请联系作者获得授权,并标注“简书作者”。
网友评论