iOS底层学习-day-18

前言-OC-runloop篇

我是一名iOS开发者, iOS底层 菜鸟的进阶之路30天。

问题

runloop 是怎么响应用户操作的, 具体流程是什么样的?

  • 由source1将系统事件捕捉,比如点击屏幕事件
  • 如何再包装成事件队列EventQueue

说说runLoop的几种状态

  • kCFRunLoopEntry = (1UL << 0),//进入
  • kCFRunLoopBeforeTimers = (1UL << 1),//即将进入timer
  • kCFRunLoopBeforeSources = (1UL << 2),//即将进入source
  • kCFRunLoopBeforeWaiting = (1UL << 5),//即将进入开始
  • kCFRunLoopAfterWaiting = (1UL << 6),//已经开始
  • kCFRunLoopExit = (1UL << 7),//退出
  • kCFRunLoopAllActivities = 0x0FFFFFFFU

runloop的mode作用是什么?

  • kCFRunLoopDefaultMode(NSDefaultRunLoopMode):App的默认Mode,通常主线程是在这个Mode下运行
  • UITrackingRunLoopMode:界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响

runloop的应用

runloop处理block

CFRunLoopPerformBlock(<#CFRunLoopRef rl#>, <#CFTypeRef mode#>, <#^(void)block#>)
  • RunLoop的运行逻辑
    在这里插入图片描述

线程间的处理 - 在子线程处理事情回到主线程

dispatch_async(dispatch_get_global_queue(0, 0), ^{
     // 处理一些子线程的逻辑
     // 回到主线程去刷新UI界面,这个依赖于runloop
     dispatch_async(dispatch_get_main_queue(), ^{
         NSLog(@"11111111111");
     });
});

runLoop解决NSTimer在滑动时停止工作的问题

	static int count = 0;
    //在defult下工作,而不在UITracking下工作,一般不用scheduled,因为它直接添加到defult
    NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
        NSLog(@"%d", ++count);
        CFRunLoopCopyCurrentMode(CFRunLoopGetCurrent());//打印模式
    }];
    // [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
    // [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
    
    // NSDefaultRunLoopMode、UITrackingRunLoopMode才是真正存在的模式
    // NSRunLoopCommonModes并不是一个真的模式,它只是一个标记
    // timer能在_commonModes数组中存放的模式下工作,_commonModes装着NSDefaultRunLoopMode,UITrackingRunLoopMode
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

runLoop控制线程生命周期(线程保活)

  • 例子1
  • MJThread类
#import <Foundation/Foundation.h>

@interface MJThread : NSThread

@end

MJThread.m
#import "MJThread.h"

@implementation MJThread

- (void)dealloc
{
    NSLog(@"%s", __func__);
}

@end
  • ViewController.m
#import "ViewController.h"
#import "MJThread.h"

@interface ViewController ()
@property (strong, nonatomic) MJThread *thread;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.thread = [[MJThread alloc] initWithTarget:self selector:@selector(run) object:nil];
    [self.thread start];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    [self performSelector:@selector(test) onThread:self.thread withObject:nil waitUntilDone:NO];//waitUntilDone YES 等执行完,再往下走,如果NO,就同时执行NSLog(@"123");
    NSLog(@"123");
}

// 子线程需要执行的任务
- (void)test
{
    NSLog(@"%s %@", __func__, [NSThread currentThread]);
}

// 这个方法的目的:线程保活
- (void)run {
    NSLog(@"%s %@", __func__, [NSThread currentThread]);
    
    // 往RunLoop里面添加Source\Timer\Observer
    [[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
    [[NSRunLoop currentRunLoop] run];
    
    NSLog(@"%s ----end----", __func__);
}

@end
  • 例子2
  • MJThread类
MJThread.h
#import <Foundation/Foundation.h>

@interface MJThread : NSThread

@end

MJThread.m
#import "MJThread.h"

@implementation MJThread

- (void)dealloc {
    NSLog(@"%s", __func__);
}

@end
  • ViewController.m
#import "ViewController.h"
#import "MJThread.h"

@interface ViewController ()
@property (strong, nonatomic) MJThread *thread;
@property (assign, nonatomic, getter=isStoped) BOOL stopped;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    __weak typeof(self) weakSelf = self;
    
    self.stopped = NO;
    self.thread = [[MJThread alloc] initWithBlock:^{
        NSLog(@"%@----begin----", [NSThread currentThread]);
        
        // 往RunLoop里面添加Source\Timer\Observer
        [[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
        while (!weakSelf.isStoped) {
            //[NSDate distantFuture] 传入一个遥远的超时的时间
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
        }
        
        NSLog(@"%@----end----", [NSThread currentThread]);
        
        // NSRunLoop的run方法是无法停止的,它专门用于开启一个永不销毁的线程(NSRunLoop)
        // [[NSRunLoop currentRunLoop] run];
        /*
         it runs the receiver in the NSDefaultRunLoopMode by repeatedly invoking runMode:beforeDate:.
         In other words, this method effectively begins an infinite loop that processes data from the run loop’s input sources and timers
         */
        
    }];
    [self.thread start];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    [self performSelector:@selector(test) onThread:self.thread withObject:nil waitUntilDone:NO];
}

// 子线程需要执行的任务
- (void)test {
    NSLog(@"%s %@", __func__, [NSThread currentThread]);
}

- (IBAction)stop {//点击按钮调用
    // 在子线程调用stop
    [self performSelector:@selector(stopThread) onThread:self.thread withObject:nil waitUntilDone:NO];
}

// 用于停止子线程的RunLoop
- (void)stopThread {
    // 设置标记为NO
    self.stopped = YES;
    
    // 停止RunLoop
    CFRunLoopStop(CFRunLoopGetCurrent());
    NSLog(@"%s %@", __func__, [NSThread currentThread]);
}

- (void)dealloc {
    NSLog(@"%s", __func__);
    //[self stop];//调用后崩溃,因为waitUntilDone选择NO,那么就是直接走dealloc的方法就直接释放了当前控制器,所以,调用stop中的self的时候,控制器已经被销毁,所以会出现坏内存访问
}

@end
  • 例子3 - 真解
  • ViewController.m
#import "ViewController.h"
#import "MJThread.h"

@interface ViewController ()
@property (strong, nonatomic) MJThread *thread;
@property (assign, nonatomic, getter=isStoped) BOOL stopped;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    
    __weak typeof(self) weakSelf = self;
    
    self.stopped = NO;
    self.thread = [[MJThread alloc] initWithBlock:^{
        NSLog(@"%@----begin----", [NSThread currentThread]);
        
        // 往RunLoop里面添加Source\Timer\Observer
        [[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];
    
        while (weakSelf && !weakSelf.isStoped) {//weakSelf因为它指向的对象要被销毁了。那么它自己就置空了
            [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
        }
        
        NSLog(@"%@----end----", [NSThread currentThread]);
    }];
    [self.thread start];
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
    if (!self.thread) return;
    [self performSelector:@selector(test) onThread:self.thread withObject:nil waitUntilDone:NO];
}

// 子线程需要执行的任务
- (void)test
{
    NSLog(@"%s %@", __func__, [NSThread currentThread]);
}

- (IBAction)stop {
    if (!self.thread) return;
    
    // 在子线程调用stop(waitUntilDone设置为YES,代表子线程的代码执行完毕后,这个方法才会往下走)
    [self performSelector:@selector(stopThread) onThread:self.thread withObject:nil waitUntilDone:YES];
}

// 用于停止子线程的RunLoop
- (void)stopThread {
    // 设置标记为YES
    self.stopped = YES;
    
    // 停止RunLoop
    CFRunLoopStop(CFRunLoopGetCurrent());
    NSLog(@"%s %@", __func__, [NSThread currentThread]);
    
    // 清空线程
    self.thread = nil;
}

- (void)dealloc {
    NSLog(@"%s", __func__);
    
    [self stop];
}

@end
发布了31 篇原创文章 · 获赞 0 · 访问量 950

猜你喜欢

转载自blog.csdn.net/weixin_41732253/article/details/103987615