一:常驻线程 :当需要一个线程一直处理一些耗时操作时,可以让它拥有一个RunLoop。具体代码如下:
1.通过给RunloopMode里加源来保证RunLoop不直接退出。
这里有个很重要得知识点,runloop对象如果mode为空得话,会直接返回。在下面这段代码中的run方法里:
[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode]; // 给RunLoop的Mode里添加内容 [[NSRunLoop currentRunLoop] run];// 开启RunLoop,默认是出于Default模式。
保证RunLoop对象的mode不会为空,也就是不会直接退出,保证线程持续运行。
@interface ViewController ()
@property (nonatomic, strong) ZZThread *testThread; @end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad]; // 创建自己的线程,并让其执行run方法
ZZThread *thread = [[ZZThread alloc] initWithTarget:self selector:@selector(run) object:nil];
self.testThread = thread;
[self.testThread start]; }
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
[self performSelector:@selector(test) onThread:self.testThread withObject:nil waitUntilDone:NO ];
}
- (void)test{
NSLog(@"%s ------- %@",__func__,[NSThread currentThread]);
}
// 给线程添加一个RunLoop 让线程"Live"
- (void)run
{
NSLog(@"%s -------------- %@",__func__,[NSThread currentThread]); // 如果RunLoop的Mode内没有内容,RunLoop会被直接销毁
[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode]; // 给RunLoop的Mode里添加内容 [[NSRunLoop currentRunLoop] run];// 开启RunLoop,默认是出于Default模式。 NSLog(@"-------------run end -----------");// 正面run方法一直没有结束 } @end
2.给Runloop中添加定时器也可以保证RunLoop直接退出。
- (void)viewDidLoad {
[super viewDidLoad]; // 创建自己的线程,并让其执行run方法
ZZThread *thread = [[ZZThread alloc] initWithTarget:self selector:@selector(test2) object:nil];
self.testThread = thread;
[self.testThread start]; } - (void)test2{ NSTimer *timer = [NSTimer timerWithTimeInterval: target:self selector:@selector(test) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode ]; [[NSRunLoop currentRunLoop] run]; }
- (void)test{
NSLog(@"%s ------- %@",__func__,[NSThread currentThread]);
}
二:自动释放池
1.RunLoop的自动释放池的生命周期
RunLoop在开始步骤1时会创建自动释放池,并将之后的需要创建的临时对象都放在池子里,然后在步骤6的时候会将池子销毁,也就是对所有对象做一次realease操作。
也就是说RunLoop每跑一圈,到休眠这个周期里,自动释放池的生命周期同时也是从创建到销毁。
2016-1-24补充:
Runloop内部是通过注册一个Observer监听RunLoop的状态,当监听到RunLoop的状态为before waiting时,就会释放自动释放池。(kCFRunLoopBeforeWaiting)
需要注意的是,Observer也会在这个时候在执行完销毁自动释放池的操作后,再创建一个自动释放池,而不是在步骤1。
也就是说RunLoop中的自动释放池都是在步骤6中销毁与创建的!!!
2016 - 1- 24 16:00再次补充:
可以打印出Runloop对象,发现它内部监听自动释放池的obserer对象的activities的值为1和160(32 + 128)
也就是说observer对象其实监听了Runloop的三个状态:kCFRunLoopEntry,kCFRunLoopBeforeWaiting,kCFRunLoopExit
kCFRunLoopEntry:Runloop的进入状态,此时会第一次创建自动释放池
kCGRunLoopBeforeWaiting: RunLoop的休眠状态前,此时会销毁第一次在进入时创建的自动释放池并又创建一个新的自动释放池。
kCFRunLoopExit: 直接销毁自动释放池
2.所以在创建RunLoop对象时应该也用一个自动释放池包住
// 给线程添加一个RunLoop 让线程"Live"
- (void)run
{
@autoreleasepool { NSLog(@"%s -------------- %@",__func__,[NSThread currentThread]); // 如果RunLoop的Mode内没有内容,RunLoop会被直接销毁
[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode]; // 给RunLoop的Mode里添加内容 [[NSRunLoop currentRunLoop] run];// 开启RunLoop,默认是出于Default模式。 NSLog(@"-------------run end -----------");// 正面run方法一直没有结束 } }