RunLoop(一)概览

486 阅读3分钟

运行循环

//main.m

int main(int argc, char * argv[])
{
  @autoreleasepool 
  {
    int a = UIApplicationMain(argc, argv ,nil ,NSStringFromClass([AppDelegate class]));
    
    NSLog(@"打印"); // 这个log不会打印。因为运行循环是个死循环,所以应用不会退出
    
    return a;
  }
}
  
//main.m

int main(int argc, char * argv[])
{
  @autoreleasepool 
  {
    NSLog(@"%@",[NSThread currentThread]); // runloop 保证线程不退出
    int a = UIApplicationMain(argc, argv ,nil ,NSStringFromClass([AppDelegate class]));
    // UIApplicationMain 会开启runloop
    NSLog(@"打印"); 
    
    return a;
  }
}
  

1、作用:

  • 保证runloop所在线程不退出
  • 负责监听事件(触摸、时钟、网络)
- (void)viewDidLoad
{
  [super viewDidLoad];
  
  // 创建Timer
  NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
  
  // 将Timer 添加到RunLoop
  [NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
}

- (void)timerMethod 
{
  NSLog(@"+1s");
}

/* 笔记:

可以正常循环打印
在滑动scrollview的时候timer暂停打印,不响应

原因:
 ui模式的优先级最高,导致默认模式下的timer不被处理
*/

2、runloop的5种模式

  1. 默认模式

    当默认模式中有事件需要处理,runloop将被唤醒,来处理默认模式中的事件,处理完后runloop继续进入休眠状态

  2. UI模式

    优先级最高,只能被ui事件唤醒,当ui模式有事件需要处理,runloop优先处理ui模式中的事件,其他模式中的事件就先不处理

- (void)viewDidLoad
{
  [super viewDidLoad];
  
  // 创建Timer
  NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
  
  // 将Timer 添加到RunLoop
  /*
  UITrackingRunLoopMode - UI模式
  */
  [NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
}

- (void)timerMethod 
{
  NSLog(@"+1s");
}

/* 笔记:

没有ui操作的情况下不打印
在滑动scrollview的时候timer响应,开始打印

原因:
 ui模式只能被ui事件唤醒
*/
  1. 占位模式(UI+默认) - NSRunLoopCommonModes

    - (void)viewDidLoad
    {
      [super viewDidLoad];
      
      // 创建Timer
      NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(timerMethod) userInfo:nil repeats:YES];
      
      // 将Timer 添加到RunLoop
    
      [NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    }
    
    - (void)timerMethod 
    {
      NSLog(@"+1s");
    }
    
    /* 笔记:
    
    没有ui操作的情况下
    和
    在滑动scrollview的时候
    timer都会响应,开始打印
    
    原因:
     timer被添加进NSRunLoopCommonModes相当于timer同事被添加进默认模式和ui模式
    */
    

3、子线程中的runloop

- (void)viewDidLoad
{
  [super viewDidLoad];
  
	NSTread *thread = [[NSThread alloc] initWithBlock:^{
    	
      // 创建Timer
  		NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self 			selector:@selector(timerMethod) userInfo:nil repeats:YES];
  
  		// 将Timer 添加到RunLoop
  		[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    
    	NSLog(@"子线程中%@",[NSTread currentThread]); // 会打印
  }];
  
  // start
  [thread start];
}

// 注:如果此时线程对象没被销毁,其线程也被销毁了,如果想保住线程的命,要么是线程中的任务没有执行完

- (void)timerMethod 
{
  [NSThread sleepForTimeInterval:1.0];
  NSLog(@"timer%@",[NSTread currentThread]); //  不会打印
}

注:

如果此时线程对象没被销毁,其线程也被销毁了,如果想保住线程的命,要么是线程中的任务没有执行完,要么开启runloop

每条线程内部都有一个runloop,但是默认都不开启

- (void)viewDidLoad
{
  [super viewDidLoad];
  
	NSTread *thread = [[NSThread alloc] initWithBlock:^{
    	
      // 创建Timer
  		NSTimer *timer = [NSTimer timerWithTimeInterval:1.0 target:self 			selector:@selector(timerMethod) userInfo:nil repeats:YES];
  
  		// 将Timer 添加到RunLoop
  		[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
    	// --重点--
    	[[NSRunLoop currentRunLoop] run];//手动开启当前线程的runloop
    	// --重点--
    
    	NSLog(@"子线程%@",[NSTread currentThread]); // 不会打印,因为上面的runloop相当于死循环
  }];
  
  // start
  [thread start];
}

// 注:如果此时线程对象没被销毁,其线程也被销毁了,如果想保住线程的命,要么是线程中的任务没有执行完

- (void)timerMethod 
{
  [NSThread sleepForTimeInterval:1.0];
  NSLog(@"timer%@",[NSTread currentThread]); //  会打印
}

4、source - 事件源

类型:

按照函数调用栈划分:

  • source0

    非source1

  • source1

    系统内核事件

5、observer - 监听runloop循环

- (void)addRunloopObserver
{
  //获取runloop
  CFRunLoopRef runloop = CFRunLoopGetCurrent();
  
  // 定义观察者
  static CFRunLoopObserverRef defaultModeObserver;
  
  // 创建上下文
  CFRunLoopObserverContext context = {
    0,
    (__bridge void *)(self),
    &CFRetain,
    &CFRelease,
    NULL
  };
  
  // 创建
  defaultModeObserver = CFRunLoopObserverCreate(NULL, kCFRunLoopBeforeWaiting, 0, &CallBack, &context);
  
  // 添加到当前runloop中
  CFRunLoopAddObserver(runloop, defaultModeObserver , kCFRunLoopDefaultMode);
  
}

void CallBack(CFRunLoopObserverRef observer, CFRunLoopActivity activity, void *info)
{
  NSLog(@"回调");
  ViewController *vc = (__bridge ViewController *)info;
}