美文网首页
Runtime 一个必须会的技能

Runtime 一个必须会的技能

作者: marlonxlj | 来源:发表于2017-01-20 14:41 被阅读20次

    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的过程,而是直触发"消息转发",时入如下流程:

    1.+ (BOOL)resolveInstanceMethod:(SEL)sel实现方法,指定是否动态添加方法。若返回NO,则进入下一步,若返回YES,则通过calss_addMethod函数动态添加方法,消息得到处理,流程完毕
    2.在第一步返回NO时,就会进入(id)forwardingTargetForSelector:(SEL)aSelector方法,这是运时给我们的第二次机会,用于指定哪个对象响应selector.不能指定self,若返回nil,表示没有响应者,则会进入第三步。若返回某个对象,则会调用该对象的方法。
    3.若第二步返回的是nil,则我们首先要通过- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector来指定方法签名,若返回nil,则表示不做处理,若返回方法签名,则会进入下一步
    4.当第三返回方法的方法签名后,就会调用- (void)forwardInvocation:(NSInvocation *)anInvocation方法,我们可以通过anInvocation对象做很多的处理,比如修改实现方法,修改响应对象等。
    5.若没有实现- (void)forwardInvocation:(NSInvocation *)anInvocation方法,就会进入-(void)doesNotRecognizeSelector:(SEL)aSelector方法,若我们没有实现这个方法,那么就会crash掉,然后提示打不到响应的方法,到此,动态解析的流程就结束了。

    2.交换方法:exchangeIMP

    🐼🐶🐶如果对你有帮助,或觉得可以。请右上角star一下,这是对我一种鼓励,让我知道我写的东西有人认可,我才会后续不断的进行完善。

    有任何问题或建议请及时issues me,以便我能更快的进行更新修复。

    Email: marlonxlj@163.com

    相关文章

      网友评论

          本文标题:Runtime 一个必须会的技能

          本文链接:https://www.haomeiwen.com/subject/xjgwbttx.html