美文网首页
Runtime(二)

Runtime(二)

作者: 952625a28d0d | 来源:发表于2017-01-18 22:09 被阅读32次
    • OC 和 C的本质区别
      C语言在编译的时候我就知道你等下会调用哪一个函数
      OC在编译的时候,不知道不要调用哪一个函数(动态编译)

    • 消息发送机制

    #import "ViewController.h"
    #import "Person.h"
    #import <objc/message.h>    // 默认导入Runtime
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
        [super viewDidLoad];
        // Do any additional setup after loading the view, typically from a nib.
        
        Person *p = [[Person alloc] init];
    //    [p run];
        
        // 在Xcode5.0之后 苹果不建议使用底层函数
        // 发送一个消息给 p
        objc_msgSend(p,@selector(run));
        objc_msgSend(p, @selector(earWithFoot:),@"香蕉");
        
        // 调用类方法 Class类型也是一个特殊的对象
        Class personClass = [Person class];
        // 不管是对象还是类 都可以发送消息
        objc_msgSend(personClass, @selector(run));
    }
    
    
    - (void)didReceiveMemoryWarning {
        [super didReceiveMemoryWarning];
        // Dispose of any resources that can be recreated.
    }
    
    
    @end
    
    #import <Foundation/Foundation.h>
    
    @interface Person : NSObject
    
    + (void)run;
    
    - (void)run;
    
    - (void)earWithFoot:(NSString *)foot;
    
    @end
    
    #import "Person.h"
    
    @implementation Person
    
    - (void)earWithFoot:(NSString *)foot{
        NSLog(@"吃%@",foot);
    }
    
    - (void)run{
        NSLog(@"跑起来了");
    }
    
    + (void)run{
        NSLog(@"类方法");
    }
    
    @end```
    
    
    - 测试
    
    ![Paste_Image.png](https://img.haomeiwen.com/i189984/211e905c33804fde.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    
    ###使用Runtime进行方法替换
    
    
    • (void)viewDidLoad {
      [super viewDidLoad];

      // 平时这么写 创建URL 但是有可能为空! 如果字符串有中文 那么发送请求就会出错 那么就会Crash 我们想不到Url为空。。
      NSURL *url = [NSURL URLWithString:@"www.baidu.com/中文"];
      NSLog(@"%@",url);

    }```

    Paste_Image.png
    • 使用Category+load实现方法交换

    1:第一步 写个url Category

    #import <Foundation/Foundation.h>
    
    @interface NSObject (url)
    
    + (instancetype)JYF_URLWithString:(NSString *)URLString;
    
    @end```
    
    
    - 第二部分 进行方法交换
    
    
    

    import "NSObject+url.h"

    import <objc/runtime.h> // 使用Runtime进行方法的交换

    @implementation NSObject (url)

    // 只要加载这个类 只要参与了加载 就会调用load方法

    • (void)load{
      NSLog(@"%s",func);
      // 1:拿到两个方法 苹果原来的URLWithString和我们自己扩展的JYFURLWithString
      // 获取类方法 class_getClassMethod 实例方法 class_getInstanceMethod
      // 参数 1:类型 2:方法编号
      Method mURLWithStr = class_getClassMethod([NSURL class], @selector(URLWithString:));
      Method mHK_URLWithStr = class_getClassMethod([NSURL class], @selector(JYF_URLWithString:));

      // 2:交换这两个方法
      method_exchangeImplementations(mURLWithStr, mHK_URLWithStr);
      }

    • (instancetype)JYF_URLWithString:(NSString *)URLString{
      NSURL *url = [NSURL JYF_URLWithString:URLString]; // 会找URLWithString这个方法 跑出去了 然后找系统的方法去执行
      if (url == nil) {
      NSLog(@"哥们是个空的Url");
      }
      return url;
      }

    @end

    
    - 测试
    
    
    ![Paste_Image.png](https://img.haomeiwen.com/i189984/cbc6b83e627ccc84.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    - 方法替换成功!!!
    
    
    
    - 降低消耗
    
    ###使用Runtime进行方法的懒加载:
    那么方法的懒加载用过么?懵逼??
    - 怎么去懒加载OC中的方法?
    
    - 先加载一个没有的方法 直接报错后 我们在m文件中进行处理
    
    
    • (void)viewDidLoad {
      [super viewDidLoad];
      // Do any additional setup after loading the view, typically from a nib.

      Person *p = [[Person alloc] init];
      // 懒加载:用到的时候再加载方法!!
      [p performSelector:@selector(eat)];
      [p performSelector:@selector(eat:) withObject:@"板烧鸡腿堡"];
      }

    
    

    import "Person.h"

    import <objc/message.h>

    @implementation Person

    // C语言
    // 所有的C语言函数都有这两个隐士参数!只要调用 系统都会传递进来!那个对象的那个方法
    void eat(id self, SEL _cmd){
    NSLog(@"调用了%@对象的%@方法",self,NSStringFromSelector(_cmd));
    NSLog(@"哥们吃了");
    }

    void eat1(id self, SEL _cmd, id obj){
    NSLog(@"哥们今晚吃五个%@", obj);
    }

    // 当这个类被外界调用了没有实现的方法!!!就会来到这里了!!!

    • (BOOL)resolveInstanceMethod:(SEL)sel{
      NSLog(@"您没有实现这个方法%@",NSStringFromSelector(sel));
      if (sel == @selector(eat)) {
      /*
      1 cls:类类型
      2 sel: 方法编号
      3 imp: 方法实现 传入函数指针!
      4 types: 函数类型 C字符串 (代码)void === "v" 需要动态判断 写法根据文档来写
      */
      class_addMethod([Person class], sel, (IMP)eat, "v@:");
      }else if (sel == @selector(eat:)){
      class_addMethod([Person class], sel, (IMP)eat1, "v@:");
      }

      return [super resolveInstanceMethod:sel];
      }

    @end

    
    - 运行之后
    ![Paste_Image.png](https://img.haomeiwen.com/i189984/06cb64bcf1cc20ae.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    

    相关文章

      网友评论

          本文标题:Runtime(二)

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