(因为run和loop是两个词所以首字母均大写)
1 创建常驻线程
主线程不死是因为主线程里面有一个RunLoop,RunLoop里面有一个do while死循环,保证了程序的不退出。那么如果我们有一个需求,需要一直在后台进行某个耗时操作,比如检查联网状态,比如扫描用户的某些行为等等。这时候肯定要在子线程进行,如果能保证一个子线程的不死,就能避免频繁的创建与销毁线程.
方法:
模仿主线程不死的操作(通过在子线程中给RunLoop添加监听者)
1.创建并强引用线程
2.往该线程里添加RunLoop
3.往RunLoop里面添加事务(source,timer,observer),保证RunLoop不退出
4.RunLoop run
这样我们就可以随时调用该线程处理一些任务了,代码如下
#import "ViewController.h"
#import "GQThread.h"
@interface ViewController ()
@property (nonatomic,strong)GQThread * thread; // 重写了dealloc方法,查看线程是够销毁
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.thread = [[GQThread alloc]initWithTarget:selfselector:@selector(threadBegin1)object:nil];
self.thread.name =@"不死线程";
[self.thread start];
}
// threadBegin123都可以让线程不死
- (void)threadBegin1 {
@autoreleasepool{ //必须的,下面两个方法也应该加上,处理一些autorelease对象,ps:一般两种情况下需要自己创建自动释放池一是短时间内创建大量的自动释放对象二是在主线程外开启其它线程时
[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];
[[NSRunLoopcurrentRunLoop] run];
NSLog(@"threadBegin");//主句代码不会执行了,因为[[NSRunLoopcurrentRunLoop] run]一直在跑圈,在RunLoop内部会不断去查看该线程有没有任务要处理,若有,就让它处理一下
}
}
- (void)threadBegin2{
while (1) {
[[NSRunLoopcurrentRunLoop] run];
}
}
- (void)threadBegin3{
// 默认创建RunLoop并向其model添加timer,所以后续只需要让RunLoop run起来即可
[NSTimer scheduledTimerWitTimeInterval:2.0 target:self selector:@selector(test)userInfo:nil repeats:YES];
[[NSRunLoopcurrentRunLoop] run];
}
// 自定义的一些任务给该线程执行
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
[self performSelector:@selector(test) onThread:self.thread withObject:nilwaitUntilDone:NO];//给线程所在的runloop添加一个source0,如果对应线程没有runloop这个方法就会失效
}
- (void)test
{
NSLog(@"***********test2*******%@", [NSThreadcurrentThread]);
// NSLog(@"%@", [NSRunLoop currentRunLoop]);
}
举例:
AFNetWorking
就使用到了常驻线程:
- 创建常驻线程
+ (void)networkRequestThreadEntryPoint:(id)__unused object {
@autoreleasepool {
[[NSThread currentThread] setName:@"AFNetworking"];
// 创建RunLoop并向Mode添加NSMachPort,使RunLoop不会退出
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[runLoop run];
}
}
+ (NSThread *)networkRequestThread {
static NSThread *_networkRequestThread = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
[_networkRequestThread start];
});
return _networkRequestThread;
}
- 使用常驻线程
- (void)start {
[self.lock lock];
if ([self isCancelled]) {
[self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
} else if ([self isReady]) {
self.state = AFOperationExecutingState;
[self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
}
[self.lock unlock];
}
2 让某些事件在特定模式下进行 (譬如定时器NSTimer)
// 图片只在NSDefaultRunLoopMode模式下会进行设置显示
[self.imageView performSelector:@selector(setImage:) withObject:[UIImage imageNamed:@"Snip20150712_39"] afterDelay:2.0 inModes:@[NSDefaultRunLoopMode]];
3 添加Observer监听RunLoop状态
// 创建监听者
CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopBeforeTimers, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
NSLog(@"%ld", activity);
});
// [[NSRunLoop currentRunLoop] getCFRunLoop]
// 向当前runloop添加监听者
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);
// 释放内存
CFRelease(observer);