zoukankan      html  css  js  c++  java
  • 【iOS之runtime、runloop】

    什么是runtime

    runtime就是运行时,是系统在运行时的一些动态机制,它是一套底层的API,我们平时编写的OC代码,最终会转换为runtime实现。

    runtime的作用

    • 可以利用runtime获取一个类的属性列表,可以通过runtime拿到一个类的所有成员属性。

       首先要导入runtime.h的头文件

    • #import <objc/runtime.h>
      此处以获取Person类(事先已经定义好,有三个成员属性age、name、height)的成员变量为例,代码如下
    •  1   // 定义一个无符号整型数字(用于记录类中的成员变量的个数)
       2     unsigned int count = 0;
       3     
       4     // 使用这个runtime函数,可以获取一个类的成员变量,返回一个ivar类型的数组
       5     Ivar *ivars = class_copyIvarList([Person class], &count);
       6     NSLog(@"%d",count); // count打印出来为3,即(person类的成员变量个数)
       7     for (int i = 0;i < count;i++) {
       8         // 获取每个成员变量
       9         Ivar memmber = ivars[i];
      10         const char *name = ivar_getName(memmber);
      11         NSLog(@"%s",name);
      12     }

      打印结果为:

      2016-01-22 08:43:37.292 c语言函数等[2528:16328] _age

      2016-01-22 08:43:37.293 c语言函数等[2528:16328] _name

      2016-01-22 08:43:37.293 c语言函数等[2528:16328] _height

      ,第5行class_copyIvarList([Person class], &count) 这个函数,第一个参数是要获取成员变量指定的那个类,第二个参数需要传递一个整型数据地址,函数内部会返回一个整数也就是指定类的成员属性个数。

    • runtime可以动态的给一个类增加方法,也可以交换自定义的方法和系统的方法的实现。

       例如在整个程序中想给 imageNamed: 这个方法添加一些额外的功能,这时候可以写一个方法来替换系统的 imageNamed:

    •  1 #import <objc/runtime.h>
       2 
       3 @implementation UIImage (Extension)
       4 /**
       5  *  只要分类被装载到内存中,就会调用1次
       6  */
       7 + (void)load
       8 {
       9     Method otherMehtod = class_getClassMethod(self, @selector(imageWithName:));
      10     Method originMehtod = class_getClassMethod(self, @selector(imageNamed:));
      11     // 交换2个方法的实现
      12     method_exchangeImplementations(otherMehtod, originMehtod);
      13 }

      可以在UIImage的分类中,使用这个runtime的 method_exchangeImplementations(otherMehtod, originMehtod) 函数,将系统的方法 imageNamed: 和自定义的方法 imageWithName: 交换实现,之后当你调用这个方法 imageNamed:时,就会使用自定义方法 imageWithName: 的实现。

    什么是runloop

    1. 其实它内部就是do-while循环,在这个循环内部不断地处理各种任务(比如SourceTimerObserver),能让线程不被系统终止
    2. 一个线程对应一个RunLoop,主线程的RunLoop默认已经启动,子线程的RunLoop得手动启动(调用run方法)
    3. RunLoop只能选择一个Mode启动,如果当前Mode中没有任何Source(Sources0Sources1)Timer,那么就直接退出RunLoop

    runloop的作用

    • 可以使用runloop,在一个子线程中长期监控某个事件
    •  1 - (void)viewDidLoad {
       2     [super viewDidLoad];
       3     // 开启一个线程让它执行run方法,如果run方法过了,线程就会死掉
       4     self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
       5     [self.thread start];
       6 }
       7 - (void)run
       8 {
       9     NSLog(@"run----%@",[NSThread currentThread]);
      10     // 给线程执行的方法添加运行时,添加source1 和timer,让这个进程不死,并在没有任务时进入休眠状态
      11     [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
      12     [[NSRunLoop currentRunLoop] run];
      13     // 可以在这里添加要循环执行的代码
      14 }

       上面的代码如果不加runloop,run方法执行完,self.thread这个线程就会被释放

    • 可以让某些事件(行为、任务)在特定模式下执行(例如轮播广告,在用户拖动图片的时候,不去循环轮播图片(不做定时任务),等用户松开手指时才开始计算循环周期(开始定时任务))
    • runloop常用的三种模式:
    1.  NSDefaultRunLoopMode:runloop默认的模式,程序启动模式主线程的runloop就是在NSDefaultRunLoopMode模式下运行的。
    2. UITrackingRunLoopMode:runloop在用户点击或触摸屏幕时,会自动切换到该模式。
    3. NSRunLoopCommonModes:指标记为common modes的所有模式,即前两者的集合。
       1 - (void)timer
       2 {
       3     NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
       4     // 定时器只运行在NSDefaultRunLoopMode下,一旦RunLoop进入其他模式,这个定时器就不会工作
       5         [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
       6 }
       7 
       8 - (void)run
       9 {
      10     NSLog(@"----run");
      11 }

       如上代码,在 NSDefaultRunLoopMode模式下添加一个定时器任务(每2秒打印一次run这个方法),程序一启动后,是NSDefaultRunLoopMode,所以一直打印,当用户触摸屏幕上的UIScrollView时,此时自动切换到UITrackingRunLoopMode,定时器停止工作,当用户松开手时,定时器重新启动,run方法继续执行打印。如果将

        如果将上面代码加入到NSRunLoopCommonModes,那么不管用户是否触摸UIScrollView,定时器都会正常工作。


  • 相关阅读:
    Ubuntu 开机启动是出现 grub rescue 解决办法
    OpenvSwitch Port Mirror in OpenStack Neutron
    Protobuf 在Ubuntu 14上的编译与使用
    Linux screen 常用命令
    OpenStack/devstack with Neutron on Ubuntu 14 (1)
    osprofiler在openstack Cinder里的使用
    基于SSH协议的端口转发
    HA 技术简介
    Socket Receive数据一次性接收不全的问题
    【转】本文对C#虚函数virtual进行详解。
  • 原文地址:https://www.cnblogs.com/heyode/p/5136601.html
Copyright © 2011-2022 走看看