iOS基础 - 线程 1.1:简介 | NSThread


概念

1 - 程序:由代码生成的可执行应用(例如:QQ.app)

2 - 进程:一个正在运行的程序可以看做是一个进程,它拥有独立运行所需要的全部资源

3 - 线程:程序中独立运行的代码段

4 - 主线程:一个正在运行的程序(即进程),至少包含一个线程,即主线程。主线程在程序启动时被创建,用于执 main 函数

5 - 单线程程序:只有一个主线程的程序

6 - 多单线程程序:拥有多个线程的程序

      一个进程行由一个或多个线程组成。进程只负责资源的调度和分配,线程才是程序执行的真正单元,负责代码的执行

      主线程负责执行程序的所有代码(UI 展示刷新、本地存储、网络请求等等),这些代码只能顺序执行,无法并发执行

      子线程和主线程都是独立运行的单元,各自执行互不影响,因此能够实现并发执行

7 - iOS UI 的添加和刷新必须在主线程中操作

并发 | 并行

1 - 并发是指一个处理器同时处理多个任务(并非真正意义上的同时,任务超速切换)

2 - 并行是指多个处理器或者是多核的处理器同时处理多个不同的任务

3 - 并发是逻辑上的同时发生,而并行是物理上的同时发生

      打个比喻,并发是指同一个人同时吃三个馒头(并不是真正意义上的同时);并行是指三个人同时吃三个馒头,人手一个(真正意义上的同时)

      当有多个线程在操作时,如果系统只有一个 CPU,则它根本不可能真正同时进行一个以上的线程

4 - 并行在多处理器系统中存在,而并发可以在单处理器和多处理器系统中都存在

5 - 并发能够在单处理器系统中存在是因为并发是并行的假象

      并行则不同,它要求程序能够同时执行多个操作

NSThread

1 - 它是一个轻量级的多线程,一个 NSThread 对象就代表一条线程

2 - 常用 API

3 - 代码示例:使用 NSThread 创建线程

 1     // 获取当前线程
 2     NSThread *current = [NSThread currentThread];
 3     NSLog(@"%@",current);// 主线程
 4 
 5     // 获取主线程
 6     NSThread *main = [NSThread mainThread];
 7     NSLog(@"%@",main);// 主线程
 8 
 9     // 开启子线程:执行一些耗时操作
10     [self creatNSThread01];
 1 // 开启子线程:
 2 -(void)creatNSThread01{
 3 
 4     // 方式一
 5     // 创建一个子线程
 6     NSThread  *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"线程A"];
 7     // 为线程设置一个名称
 8     thread.name = @"线程A";
 9     // 开启子线程
10     [thread start];
11 
12     // 同样,再次创建一个子线程
13     NSThread  *thread2 = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"线程B"];
14     thread2.name=@"线程B";
15     [thread2 start];
16 
17 
18     // 方式二
19     [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"创建完线程直接启动,不需要手动开启"];
20 
21     // 方式三:隐式创建线程,并且直接启动
22     [self performSelectorInBackground:@selector(run:) withObject:@"隐式创建"];
23 
24 }
1 -(void)run:(NSString *)str{
2 
3     NSThread *current = [NSThread currentThread];
4     for (int i = 0; i < 5; i++) {
5          // 三个子线程轮流切换输出
6          NSLog(@"run---%@---%@",current,str);
7     }
8 }

日志打印

4 - NSThread 其它常用 API

 1 - (BOOL)isMainThread; // 是否为主线程
 2 + (BOOL)isMainThread; // 是否为主线程
 3 
 4 // 线程的调度优先级:调度优先级的取值范围是 0.0 ~ 1.0,默认 0.5,值越大,优先级越高
 5 + (double)threadPriority;
 6 + (BOOL)setThreadPriority:(double)p;
 7 
 8 // 设置线程的名字
 9 - (void)setName:(NSString *)n;
10 - (NSString *)name;

5 - 代码示例:验证线程执行环境(主线程遍历会阻塞八卦图旋转;子线程遍历则与八卦图旋转同时进行)

 1 #import "ViewController.h"
 2 #define MainScreen_W    [UIScreen mainScreen].bounds.size.width
 3 @interface ViewController ()
 4 
 5 @property(strong,nonatomic)UIImageView *gossipIV;// 八卦图
 6 
 7 @end
 8 
 9 @implementation ViewController
10 
11 - (void)viewDidLoad {
12     [super viewDidLoad];
13 
14     self.gossipIV = [[UIImageView alloc] initWithFrame:CGRectMake((MainScreen_W-220)/2.0, 80, 220, 220)];
15     _gossipIV.image = [UIImage imageNamed:@"gossip.jpg"];
16     [self.view addSubview:_gossipIV];
17     
18     UIButton *btn = [UIButton buttonWithType:UIButtonTypeCustom];
19     [btn setTitle:@"阻塞" forState:UIControlStateNormal];
20     btn.backgroundColor = [UIColor redColor];
21     btn.frame = CGRectMake(40, 400, MainScreen_W-80, 40);
22     [btn addTarget:self action:@selector(chokeIV) forControlEvents:UIControlEventTouchUpInside];
23     [self.view addSubview:btn];
24     
25     UIButton *btnB = [UIButton buttonWithType:UIButtonTypeCustom];
26     [btnB setTitle:@"子线程" forState:UIControlStateNormal];
27     btnB.backgroundColor = [UIColor redColor];
28     btnB.frame = CGRectMake(100, 500, MainScreen_W-200, 40);
29     [btnB addTarget:self action:@selector(noChokeIV) forControlEvents:UIControlEventTouchUpInside];
30     [self.view addSubview:btnB];
31 
32     [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(ratateImageView) userInfo:nil repeats:YES];// 定时旋转,用来查看线程阻塞状况
33 }
34 
35 // 旋转的八卦图
36 - (void)ratateImageView{
37 
38     self.gossipIV.transform = CGAffineTransformRotate(self.gossipIV.transform, M_PI_4/4);
39 }
40 
41 // 默认主线程:遍历完成之前,八卦图被阻塞(静止不动)
42 -(void)chokeIV{
43     
44     for (int i = 0; i < 5; i++) {
45         [NSThread sleepForTimeInterval:0.5];// 线程休眠
46         NSString *str = [NSString stringWithFormat:@"i = %d",i];
47         NSLog(@"%@", str);// 线程休眠后,0.5秒一输出
48     }
49 }
50 
51 // 使用子线程:八卦图继续旋转,遍历同样正常打印
52 -(void)noChokeIV{
53     
54     [NSThread detachNewThreadSelector:@selector(test01) toTarget:self withObject:nil];
55 }
56 
57 -(void)test01{
58     
59     /* MRC 模式下,子线程中处理的操作需要自己加自动释放池
60      
61      @autoreleasepool {
62      
63          for (int i = 0; i < 5; i++) {
64              [NSThread sleepForTimeInterval:0.5];// 线程休眠
65              NSString *str = [NSString stringWithFormat:@"i = %d",i];
66              NSLog(@"%@", str);// 线程休眠后,0.5秒一输出
67          }
68      }
69      */
70     
71     for (int i = 0; i < 10; i++) {
72         [NSThread sleepForTimeInterval:0.5];// 线程休眠
73         NSString *str = [NSString stringWithFormat:@"i = %d",i];
74         NSLog(@"%@", str);// 线程休眠后,0.5秒一输出
75     }
76     
77     // 子线程不做刷新 UI 的事情,因为可能会导致刷新失败
78     [self performSelectorOnMainThread:@selector(updateUI) withObject:nil waitUntilDone:YES];// 等待遍历完成,才会执行此行代码
79     /* 在子线程中,NSTimer 是默认不能使用。如果想要使用,则需要配合开启循环事件
80      
81         [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(ratateImageView) userInfo:nil repeats:YES];// 不开启,不触发
82         [[NSRunLoop currentRunLoop] run];// 开启事件循环
83     */
84 }
85 
86 // 更新 UI
87 -(void)updateUI{
88     
89     self.view.backgroundColor = [UIColor cyanColor];
90 }
91 
92 @end

运行效果

素材链接

https://pan.baidu.com/s/1kDEpvujHJTRoTm-DrBtYSA

kn07

相关