【原文地址】
保证线程的长时间存活
在iOS开发过程中,有时一些花费时间比较长的操作阻塞主线程,导致界面卡顿,那么我们就会创建一个子线程,然后把这些花费时间比较长的操作放在子线程中来处理。可是当子线程中的任务执行完毕后,子线程就会被销毁掉。
首先,我们创建一个testThread类,继承自NSThread,然后重写dealloc 方法。
@interface testThread : NSThread
@end
@implementation testThread
- (void)dealloc
{
NSLog(@"%s",__func__);
}
@end
1
2
3
4
5
6
7
8
9
10
11
- (void)viewDidLoad
{
[super viewDidLoad];
// 测试线程
[self threadTest];
}
- (void)threadTest
{
testThread *subThread = [[testThread alloc] initWithTarget:self selector:@selector(subThreadAction) object:nil];
[subThread start];
}
- (void)subThreadAction
{
@autoreleasepool {
NSLog(@"%@----子线程任务开始",[NSThread currentThread]);
[NSThread sleepForTimeInterval:2.0];
NSLog(@"%@----子线程任务结束",[NSThread currentThread]);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
当子线程中的任务执行完毕后,线程就被立刻销毁了。
如果程序中,需要经常在子线程中执行任务,频繁的创建和销毁线程,会造成资源的浪费。
这时候我们就可以使用RunLoop来让该线程长时间存活而不被销毁。
#import "SubViewController.h"
#import "testThread.h"
@interface SubViewController ()
@property(nonatomic,strong) testThread* ttThread;
@end
@implementation SubViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// 测试线程
[self threadTest];
}
- (void)threadTest
{
testThread *subThread = [[testThread alloc] initWithTarget:self selector:@selector(subThreadEnter) object:nil];
[subThread setName:@"测试线程"];
[subThread start];
self.ttThread = subThread;
}
/**
子线程任务
*/
- (void)subThreadAction
{
NSLog(@"启动RunLoop后--%@",[NSRunLoop currentRunLoop].currentMode);
NSLog(@"%@----子线程任务开始",[NSThread currentThread]);
for (int i=0; i<300; i++)
{
[NSThread sleepForTimeInterval:1.0];
NSLog(@"----子线程任务 %ld",(long)i);
}
NSLog(@"%@----子线程任务结束",[NSThread currentThread]);
}
/**
子线程启动后,启动runloop
*/
- (void)subThreadEnter
{
@autoreleasepool {
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
//如果注释了下面这一行,子线程中的任务并不能正常执行
[runLoop addPort:[NSMachPort port] forMode:NSRunLoopCommonModes];
NSLog(@"启动RunLoop前--%@",runLoop.currentMode);
[runLoop run];
}
}
- (void)touchesBegan:(NSSet
{
[self performSelector:@selector(subThreadAction) onThread:self.ttThread withObject:nil waitUntilDone:NO];
}
@end
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
1.获取RunLoop只能使用 [NSRunLoop currentRunLoop] 或 [NSRunLoop mainRunLoop];
2.即使RunLoop开始运行,如果RunLoop 中的 modes 为空,或者要执行的mode里没有item,那么RunLoop会直接在当前loop中返回,并进入睡眠状态。
3.自己创建的Thread中的任务是在kCFRunLoopDefaultMode这个mode中执行的。
4.在子线程创建好后,最好所有的任务都放在AutoreleasePool中。
如果不执行下列语句:
[runLoop addPort:[NSMachPort port] forMode:NSRunLoopCommonModes];
执行下列语句:
[runLoop addPort:[NSMachPort port] forMode:NSRunLoopCommonModes];
可以看出我们添加了一个source0,这样runloop才运行起来。
其实这个例子只是简单制造一个常驻内存的线程,但是这个线程并不好控制结束,可以参考我的另外一篇文章iOS开发-RunLoop的退出方式。