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; }