Runtime 一个必须会的技能
前言:
Runtime是iOS的一个运行时机制,在iOS的开发中很多时候会使用到。在大部分时候很多的人总是一知半解的,有一种朦胧之感,似识非识的感觉。所在就找了很多的资料,也看别人的视频。在此做一个笔记,以便忘记了好查找。
Demo下载地址
objc_class类
struct objc_class
{
// isa指针指向Meta Class,因为Objc的类的本身也是一个Object,
// 为了处理这个关系,runtime就创造了Meta Class,
// 当给类发送[NSObject alloc]这样消息时,实际上是把这个消息发给了Class Object
Class isa OBJC_ISA_AVAILABILITY;
#if !__OBJC2__
Class super_class OBJC2_UNAVAILABLE; // 父类
const char *name OBJC2_UNAVAILABLE; // 类名
long version OBJC2_UNAVAILABLE; // 类的版本信息,默认为0
long info OBJC2_UNAVAILABLE; // 类信息,供运行期使用的一些位标识
long instance_size OBJC2_UNAVAILABLE; // 该类的实例变量大小
struct objc_ivar_list *ivars OBJC2_UNAVAILABLE; // 该类的成员变量链表
struct objc_method_list **methodLists OBJC2_UNAVAILABLE; // 方法定义的链表
// 方法缓存,对象接到一个消息会根据isa指针查找消息对象,
// 这时会在method Lists中遍历,
// 如果cache了,常用的方法调用时就能够提高调用的效率。
// 这个方法缓存只存在一份,不是每个类的实例对象都有一个方法缓存
// 子类会在自己的方法缓存中缓存父类的方法,父类在自己的方法缓存中也会缓存自己的方法,而不是说子类就不缓存父类方法了
struct objc_cache *cache OBJC2_UNAVAILABLE;
struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 协议链表
#endif
} OBJC2_UNAVAILABLE;
objc在向一个对象发送消息时,runtime库会根据对象的isa指针找到该对象实际所属的类,然后在该类中的方法列表以及其父类方法列表中寻找方法运行,然后再发送消息的时候,objc_msgSend方法不会返回值,所谓的返回内容都是具体调用时执行的。
如果向一个nil对象发送消息,首先在寻找对象的isa指针时就是0地址返回了,所以不会出现任何错误
objc_ivar_list和objc_method_list
//成员列表
struct objc_ivar_list {
int ivar_count
OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space
OBJC2_UNAVAILABLE;
#endif
/* variable length structure */
struct objc_ivar ivar_list[1]
OBJC2_UNAVAILABLE;
}
OBJC2_UNAVAILABLE;
//方法列表
struct objc_method_list {
struct objc_method_list *obsolete
OBJC2_UNAVAILABLE;
int method_count
OBJC2_UNAVAILABLE;
#ifdef __LP64__
int space
OBJC2_UNAVAILABLE;
#endif
/* variable length structure */
struct objc_method method_list[1]
OBJC2_UNAVAILABLE;
}
1.关联性
//关联对象,绑定
/**
* 1.目标
* 2.标识id
* 3.value就是值,在此处是号码
* 4.策略
*/
objc_setAssociatedObject(alert, CallBtnKey,[NSString stringWithFormat:@"%@",_dataSource[indexPath.row]], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
在需要接收关联的结果的地方进行处理:
//取出关联的值
NSString *str = objc_getAssociatedObject(alertView, CallBtnKey);
NSString *callStr = [NSString stringWithFormat:@"tel://%@",str];
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:callStr]];
给Category绑定方法
#import <UIKit/UIKit.h>
#import <objc/runtime.h>
typedef void (^TapBlock)(UIButton *sender);
@interface UIButton (XLJBlock)
- (void)tapWithEvent:(UIControlEvents )controlEvent withBlock:(TapBlock)tapBlock;
@end
#import "UIButton+XLJBlock.h"
static const void *ButtonKey = &ButtonKey;
@implementation UIButton (XLJBlock)
- (void)tapWithEvent:(UIControlEvents)controlEvent withBlock:(TapBlock)tapBlock
{
objc_setAssociatedObject(self, ButtonKey, tapBlock, OBJC_ASSOCIATION_COPY_NONATOMIC);
[self addTarget:self action:@selector(buttonClick:) forControlEvents:controlEvent];
}
- (void)buttonClick:(UIButton *)sender
{
TapBlock tapBlock = objc_getAssociatedObject(sender, ButtonKey);
if (tapBlock) {
tapBlock(sender);
}
}
@end
- 可以利用
method_exchangeImplementations
来交换2个方法的IMP - 可以利用
class_replaceMethod
方法来替换原有的方法 - 可以利用
method_setImplementation
来直接设置某个方法的IMP
消息机制
//需要包含这个头文件
#import <objc/message.h>
//消息事件,修改按钮的背景颜色为橙色;原来为红色
objc_msgSend(btn, @selector(setBackgroundColor:), [UIColor orangeColor]);
objc_msgForward消息转发
_objc_msgForward
是IMP类型,用于消息转发:当向一个对象发送一条消息,但它并没有实现的时候,_objc_msgForward
会尝试做消息转发。
IMP msgForward = _objc_msgForward
;如果手动调用objcmsgForward
,将跳过查找IMP的过程,而是直触发"消息转发",时入如下流程:
网友评论