RunTime/RunLoop

作者: Li_Po | 来源:发表于2020-10-15 17:18 被阅读0次

    Runtime

    runtime源码地址
    https://opensource.apple.com/source/objc4/
    runloop源码地址
    https://opensource.apple.com/tarballs/CF/

    所有对象都是ID类型,对应runtime就是objc_object,结构体构成


    image.png
    image.png
    image.png
    image.png
    image.png
    image.png
    image.png
    image.png
    image.png
    image.png
    image.png
    image.png
    image.png
    image.png
    image.png
    image.png

    [self class]和[super class]都是调用当前对象

    image.png
    image.png
    image.png
    image.png
    • 消息转发


      image.png
    #import "RuntimeObject.h"
    #import <objc/runtime.h>
    @implementation RuntimeObject
    void testImp (void)
    {
    NSLog(@"test invoke");
    }
    //动态方法解析 添加方法 第一次机会 lp
    + (BOOL)resolveInstanceMethod:(SEL)sel
    {
    // 如果是test方法 打印日志
    if (sel == @selector(test)) {
        NSLog(@"resolveInstanceMethod:");
        // 动态添加test方法的实现
        class_addMethod(self, @selector(test), testImp, "v@:");
        return YES;
    }
    else{
        // 返回父类的默认调用
        return [super resolveInstanceMethod:sel];
    }
    }
    //动态方法解析 转发消息 第二次机会 lp
    - (id)forwardingTargetForSelector:(SEL)aSelector
    {
    if (aSelector == @selector(test)) {
        NSLog(@"forwardingTargetForSelector:");
        return nil;
    }
    return [super forwardingTargetForSelector:aSelector];
    }
    //方法签名 lp
    - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
    {
    if (aSelector == @selector(test)) {
        NSLog(@"methodSignatureForSelector:");
        //返回方法签名
        // v 代表返回值是void类型的  @代表第一个参数类型是id,即      self
        // : 代表第二个参数是SEL类型的  即@selector(test)
        return [NSMethodSignature signatureWithObjCTypes:"v@:"];
    }
    else{
        return [super methodSignatureForSelector:aSelector];
    }
    }
    //消息转发
    - (void)forwardInvocation:(NSInvocation *)anInvocation
    {
    NSLog(@"forwardInvocation:");
    }
    

    方法交换


    image.png
    image.png

    Method m1 = class_getClassMethod([NSURL class], @selector(URLWithString:));
    Method m2 = class_getClassMethod([NSURL class], @selector(LP_URLWithString:));
    method_exchangeImplementations(m1, m2);

    image.png

    RunLoop

    • 什么是RunLoop
      RunLoop是通过内部维护的事件循环来对事件/消息进行管理的一个对象。
      没有消息需要处理时,休眠以避免资源占用(通过系统调用mach_msg(),用户态->内核态)
      有消息处理时立刻唤醒(内核态->用户态)
      维护的事件循环可以不断地处理消息或事件,然后对其进行管理。
    image.png
    image.png
    image.png
    image.png
    #import "ViewController.h"
    typedef void (^runloopBlock)(void);
    
    @interface ViewController ()<UITableViewDelegate,UITableViewDataSource>
    
    @property (nonatomic,strong)UITableView *tableView;
    @property (nonatomic,strong)NSMutableArray *taskArray;
    @property (nonatomic,assign)NSUInteger maxTaskCount;
    @property (nonatomic,strong)NSTimer * timer;
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
    [super viewDidLoad];    
    //rujnloop 的使用
    
    //创建定时任务
    CADisplayLink * play = [CADisplayLink displayLinkWithTarget:self selector:@selector(doSomeThing)];
    [play addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
    
    //_timer = [NSTimer scheduledTimerWithTimeInterval:0.001 target:self selector:@selector(doSomeThing) userInfo:nil repeats:YES];
    
    _taskArray = [NSMutableArray array];
    _maxTaskCount = 20;
    
    //添加runloop观察者
    [self addRunloopObserver];
    
    [self.view addSubview:self.tableView];
    }
    
    -(UITableView *)tableView{
    if (!_tableView) {
        _tableView = [[UITableView alloc]initWithFrame:CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height) style:UITableViewStylePlain];
        _tableView.delegate = self;
        _tableView.dataSource = self;
    }
    return _tableView;
    }
    - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
    return 50;
    }
    - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
    static NSString * cellStr = @"cell";
    TableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:cellStr];
    if (!cell) {
        cell = [[TableViewCell alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellStr];
    }
    cell.myLable.text = [NSString stringWithFormat:@"显示第%ld张图片",indexPath.row];
    [self addtask:^{
        cell.myImageView1.image = [UIImage imageNamed:@"timg.jpg"];
    }];
    [self addtask:^{
        cell.myImageView2.image = [UIImage imageNamed:@"timg.jpg"];
    }];
    [self addtask:^{
        cell.myImageView3.image = [UIImage imageNamed:@"timg.jpg"];
    }];
    [self addtask:^{
        cell.myImageView4.image = [UIImage imageNamed:@"timg.jpg"];
    }];
    [self addtask:^{
        cell.myImageView5.image = [UIImage imageNamed:@"timg.jpg"];
    }];
    
    
    return cell;
    }
    
    - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return 80;
    }
    
    #pragma mark runloop-- c语言代码
    -(void)doSomeThing{
    //z不做事情 只是让runloop一直运行
    }
    -(void)addtask:(runloopBlock)task{
    //添加任务
    [_taskArray addObject:task];
    if (_taskArray.count>_maxTaskCount) {
        [_taskArray removeObjectAtIndex:0];
      }
    }
    static void callBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info){
    //取出任务执行
    
    ViewController * vc = (__bridge ViewController *)info;
    if (vc.taskArray.count==0) {
        return;
    }
    runloopBlock block = [vc.taskArray firstObject];
    if (block) {
        block();
    }
    [vc.taskArray removeObjectAtIndex:0];
    
    }
    
    -(void)addRunloopObserver{
    
    //拿到当前的runloop
    CFRunLoopRef runloop = CFRunLoopGetCurrent();
    
    //定义上下文
    CFRunLoopObserverContext context = {
        0,
        (__bridge void *)(self),
        &CFRetain,
        &CFRelease,
        NULL
    };
    //定义一个观察车
    static CFRunLoopObserverRef  defaultModeObserver;
    //创建一个观察者
    defaultModeObserver = CFRunLoopObserverCreate(NULL, kCFRunLoopAfterWaiting, YES, 0, &callBack, &context);
    
    CFRunLoopAddObserver(runloop, defaultModeObserver, kCFRunLoopCommonModes);
    
    CFRelease(defaultModeObserver);
     }
    
    @end
    
    • 怎样实现一个常住线程
    @implementation MCObject
    
    static NSThread *thread = nil;
    // 标记是否要继续事件循环
    static BOOL runAlways = YES;
    
    + (NSThread *)threadForDispatch{
        if (thread == nil) {
            @synchronized(self) {
                if (thread == nil) {
                    // 线程的创建
                    thread = [[NSThread alloc] initWithTarget:self selector:@selector(runRequest) object:nil];
                    [thread setName:@"com.imooc.thread"];
                    //启动
                    [thread start];
                }
            }
        }
        return thread;
    }
    
    + (void)runRequest
    {
        // 创建一个Source
        CFRunLoopSourceContext context = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
        CFRunLoopSourceRef source = CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
        
        // 创建RunLoop,同时向RunLoop的DefaultMode下面添加Source
        CFRunLoopAddSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
        
        // 如果可以运行
        while (runAlways) {
            @autoreleasepool {
                // 令当前RunLoop运行在DefaultMode下面
                CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1.0e10, true);
            }
        }
        
        // 某一时机 静态变量runAlways = NO时 可以保证跳出RunLoop,线程退出
        CFRunLoopRemoveSource(CFRunLoopGetCurrent(), source, kCFRunLoopDefaultMode);
        CFRelease(source);
    }
    

    相关文章

      网友评论

        本文标题:RunTime/RunLoop

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