iOS基础 - NSThread | NSObject

▶ 前言

进程:一个正在运行的程序可以看做是一个进程,它拥有独立运行所需要的全部资源;一个进程行由一个或多个线程组成;进程只负责资源的调度和分配,线程才是程序执行的真正单元(负责代码的执行)

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

主线程:一个正在运行的程序(即进程),至少包含一个线程,就是主线程,它在程序启动时被创建

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

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

多线程程序:拥有多个线程的程序

并发是指一个处理器同时处理多个任务,并非真正意义上的同时,其实质是任务间的超速轮切!并发是逻辑上的同时发生,而并行是物理上的同时发生,打个比喻,并发是指同一个人同时吃三个馒头(并不是真正意义上的同时);

并行是指多个处理器或者是多核的处理器同时处理多个不同的任务!并行是指三个人同时吃三个馒头(真正意义上的同时)。注:当有多个线程在操作时如果系统只有一个 CPU,则它根本不可能实现真正的多线程

▶ NSObject | NSThread

A. NSObject 存在一个最简单的后台执行方法 

- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg

B. NSThread 是一个轻量级多线程,一个 NSThread对象 就代表一条线程

- (instancetype)initWithTarget:(id)target selector:(SEL)selector object:(nullable id)argument;     // 开辟一个线程(需手动开启)
- (instancetype)initWithBlock:(void (^)(void))block;
 
+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(nullable id)argument;// 开辟一个线程(自动开启)
+ (void)detachNewThreadWithBlock:(void (^)(void))block);
 
- (void)cancel; // 取消线程
- (void)start;  // 开启线程
// 是否主线程
- (BOOL)isMainThread;
+ (BOOL)isMainThread;

// 调度优先级:取值范围是 0.0 ~ 1.0,默认 0.5(值越大则优先级越高)
+ (double)threadPriority;
+ (BOOL)setThreadPriority:(double)p;

// 线程名
- (void)setName:(NSString *)n;
- (NSString *)name;

开辟线程

 1 -(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
 2     
 3     // 当前线程
 4     NSThread *CTH = [NSThread currentThread];
 5     NSLog(@"%@",CTH); // <_NSMainThread: 0x600002a240c0>{number = 1, name = main}
 6     // 主线程
 7     NSThread *MTH = [NSThread mainThread];
 8     NSLog(@"%@",MTH); // <_NSMainThread: 0x600002a240c0>{number = 1, name = main}
 9     
10     //------------------------------------------
11     
12     // 方式一
13     // 开辟一个线程 threadA
14     NSThread *threadA = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"threadA"];
15     threadA.name = @"线程A";
16     [threadA start]; // 手动开启
17     // 以同样的方式开辟一个线程 threadB
18     NSThread *threadB = [[NSThread alloc] initWithTarget:self selector:@selector(run:) object:@"threadB"];
19     threadB.name = @"线程B";
20     [threadB start];
21     
22     
23     // 方式二
24     // 开辟一个线程 threadC:自动开启
25     [NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"threadC:自动开启"];
26     
27     
28     // 方式三:NSObject
29     // 开辟一个线程 threadD:自动开启
30     [self performSelectorInBackground:@selector(run:) withObject:@"threadD:隐式创建且自动开启"];
31     
32 }
33 
34 -(void)run:(NSString *)str{
35 
36     NSThread *current = [NSThread currentThread];
37     for (int i = 0; i < 5; i++) {
38          // 验证多线程是以轮切方式工作的
39          NSLog(@"run%d---%@:%@",i,current,str);
40     }
41 }

日志信息

线程阻塞:下面代码中,在主线程中执行动画。当有一个耗时操作同样要在主线程执行时,就会阻塞当前动画运行!而使用多线程就可以保证动画、耗时操作两者 "同时" 运行 

 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     // 八卦图
15     self.gossipIV = [[UIImageView alloc] initWithFrame:CGRectMake((MainScreen_W-220)/2.0, 80, 220, 220)];
16     _gossipIV.image = [UIImage imageNamed:@"gossip.jpg"];
17     [self.view addSubview:_gossipIV];
18 
19     // 耗时操作:主线程
20     UIButton *mainBT = [UIButton buttonWithType:UIButtonTypeCustom];
21     [mainBT setTitle:@"耗时操作:主线程" forState:UIControlStateNormal];
22     [mainBT setTitle:@"" forState:UIControlStateHighlighted];
23     mainBT.backgroundColor = [UIColor redColor];
24     mainBT.frame = CGRectMake(40, 400, MainScreen_W-80, 40);
25     [mainBT addTarget:self action:@selector(chokeIV) forControlEvents:UIControlEventTouchUpInside];
26     [self.view addSubview:mainBT];
27 
28     // 耗时操作:子线程
29     UIButton *threadBT = [UIButton buttonWithType:UIButtonTypeCustom];
30     [threadBT setTitle:@"耗时操作:子线程" forState:UIControlStateNormal];
31     [threadBT setTitle:@"" forState:UIControlStateHighlighted];
32     threadBT.backgroundColor = [UIColor redColor];
33     threadBT.frame = CGRectMake(75, 500, MainScreen_W-150, 40);
34     [threadBT addTarget:self action:@selector(noChokeIV) forControlEvents:UIControlEventTouchUpInside];
35     [self.view addSubview:threadBT];
36 
37     // 使用定时器实现动画旋转:运行在主线程
38     [NSTimer scheduledTimerWithTimeInterval:0.2 target:self selector:@selector(ratateImageView) userInfo:nil repeats:YES];
39 }
40 
41 // 旋转动画
42 - (void)ratateImageView{
43     self.gossipIV.transform = CGAffineTransformRotate(self.gossipIV.transform, M_PI_4/4);
44 }
45 
46 // 在遍历完成之前,动画处受阻状态(会静止不动)
47 - (void)chokeIV{
48 
49     for (int i = 0; i < 5; i++) {
50         // 线程休眠
51         [NSThread sleepForTimeInterval:0.5];
52         NSString *str = [NSString stringWithFormat:@"i = %d",i];
53         NSLog(@"%@", str);
54     }
55 }
56 
57 // 动画、遍历同时进行
58 - (void)noChokeIV{
59     [NSThread detachNewThreadSelector:@selector(timeConsuming) toTarget:self withObject:nil];
60 }
61 
62 - (void)timeConsuming{
63 
64     // ARC 环境
65     for (int i = 0; i < 10; i++) {
66         [NSThread sleepForTimeInterval:0.5];
67         NSString *str = [NSString stringWithFormat:@"i = %d",i];
68         NSLog(@"%@", str);
69     }
70 
71     // 回到主线程刷新 UI
72     [self performSelectorOnMainThread:@selector(updateUI) withObject:nil waitUntilDone:YES];
73 
74 //--------------------- NSTimer 在子线程中使用 -------------------
75 //    // 子线程中 NSTimer 是默认不能使用,如果想要使之生效,则需要开启循环事件
76 //    [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(ratateImageView) userInfo:nil repeats:YES];
77 //    // 开启循环事件
78 //    [[NSRunLoop currentRunLoop] run];
79 //    // 如果在子线程执行动画,虽不会发生致命错误,但会有警告,如下
80 //    // [UIView transform] must be used from main thread only
81 
82 //---------------------- MRC环境中 ------------------------
83 //    // MRC 环境下,子线程中处理的操作需要添加自动释放池
84 //    @autoreleasepool {
85 //
86 //        for (int i = 0; i < 5; i++) {
87 //            [NSThread sleepForTimeInterval:0.5];
88 //            NSString *str = [NSString stringWithFormat:@"i = %d",i];
89 //            NSLog(@"%@", str);
90 //        }
91 //    }
92 }
93 
94 // 更新 UI
95 - (void)updateUI{
96     self.view.backgroundColor = [UIColor cyanColor];
97 }
98 
99 @end

运行效果:UI更新前   |   UI更新后 

         

 

posted on 2021-07-26 22:27  低头捡石頭  阅读(42)  评论(0编辑  收藏  举报

导航