#import "ViewController.h"
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UIImageView *imageVIew;
/** 线程*/
@property (nonatomic, strong) NSThread *thread;
@end
@implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// [self observer];
// [self showImage];
// [self timer];
/**
* 首先我们要让子线程不会在代码块执行完之后挂掉,所以要把线程变为全局
*/
self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(execute) object:nil];
[self.thread start];
}
- (void)execute
{
NSLog(@"线程开启");
/*
* 如果什么都不做,那么这个RunLoop没有timer,source,observer那么刚运行就会关闭
*/
//给当前线程添加一个定时器那么就不会关闭了
// [self timer];
//也可以给当前线程添加一个source事件
// [[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
//也可以添加一个observer事件
[[NSRunLoop currentRunLoop] run];
NSLog(@"----如果输出了说明NSRunLoop刚跑起来就结束了");
}
/*
* RunLoop从表面意思来看就是说跑圈或者是说循环,但是真正在程序中的表现,就像是一个do-while循环,正是这个循环才让你的程序不至于一开始就死亡。
* RunLoop一直在循环的监听处理各种事件。比如定时器事件,Sourse事件,Observer事件
* 同时呢,RunLoop如果没有这些事件,那么RunLoop就会直接退出
* RunLoop同时只能运行一种Mode,RunLoop有五种运行模式,但是只有两种是经常用到的,那就是DefaultMode和TrackingMode,DefaultMode下处理各种事件比如时钟,触摸事件,点击事件等大部分事件,而TrackingMode是RunLoop为了处理scrollView的滑动事件而产生的Mode,为的就是让在滑动过程中,不受其他事件的影响。所以说,如果想让某个事件在滑动的时候依旧能运行的话,那么就让这个事件处于TrackingMode
* RunLoop 有两套框架,一套是CFRunLoopRef ,另一套是NSRunLoop,通过名字应该也知道CFRunLoopRef是基于C的一套框架,而NSRunLoop则是对CFRunLoopRef的一种封装,更加的面向对象。
*/
/*
* 我们可以监听RunLoop的状态改变
*/
- (void)observer
{
//这里创建一个observer观察的事件,系统给了两种创建方式,但是这一种明显更简单
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
NSLog(@"-----RunLoop的状态----%zd",activity);
});
//创建之后需要添加观察者:监听RunLoop的状态
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
/*
* CF的内存管理 (CoreFoundation)
* 1.凡是带有create、copy、retain等字眼的函数,创建出来的对象,都需要在最后做一次release
* 2.release函数:(CFRelease(对象))
*/
//释放Observer
CFRelease(observer);
/*
* 打印为:1 - 2 - 4 - 2 - 4 - 2 - 4 - 32 - 64 - 2 - 4 ……
* 从打印我们可以看出,RunLoop是一个循环,开始进入RunLoop之后就开始处理Timer事件
然后处理Source0事件再通知下RunLoop要睡眠了。然后就进入睡眠状态,开发者可以通过监听这些状态来做一些事件
*/
}
/**
* 解决定时器在滚动的时候不执行的问题
*/
- (void)timer
{
/*
* 平常我们使用这种方法启动定时器,这种方式启动返回的定时器,已经自动被添加到当前的RunLoop中(一般在主线的RunLoop如果没有开启子线程的RunLoop的话),而且Mode是NSDefaultRunLoopMode,在这种方式下,如果我们滑动scrollView,这个计时器就会暂停
*/
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
/*
* 这种方式需要你来把定时器添加到RunLoop中才会工作
*/
// NSTimer *timer = [NSTimer timerWithTimeInterval:2.0 target:self selector:@selector(run) userInfo:nil repeats:YES];
/*
* 如果想要在滚动的时候也能滑动的话,那么就修改Mode为UITrackingRunLoopMode
* 在苹果中NSRunLoopCommonModes包括NSDefaultRunLoopMode和UITrackingRunLoopMode模式
*/
// [[NSRunLoop currentRunLoop] addTimer:timer forMode:UITrackingRunLoopMode];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}
- (void)run
{
NSLog(@"---run-----%@", [NSThread currentThread]);
}
/**
* 为了提升用户的体验,不至于用户在滑动页面的时候感觉到卡顿,我们可以把耗时操作放在NSDefaultRunLoopMode中进行操作
* 比如图片的渲染就是一个比较耗时的操作,我们让图片再用户停止滑动的时候再进行渲染
*/
- (void)showImage
{
[self.imageVIew performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"share"] afterDelay:3 inModes:@[NSDefaultRunLoopMode]];
}
/*
* 我们可以让子线程长存,进行某些活动
*/
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self performSelector:@selector(test) onThread:self.thread withObject:nil waitUntilDone:NO];
}
- (void)test
{
NSLog(@"----test----%@", [NSThread currentThread]);
}