iOS开发-使用Runloop实现线程保活、线程常驻

【原文地址】

保证线程的长时间存活 
在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 *)touches withEvent:(UIEvent *)event
{
    [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的退出方式。
 

你可能感兴趣的:(iOS开发)