当用户下载资源,进行图像处理,耗时数据处理等任务时 往往希望操作这个任务的时候 其他操作不会被中断 这时候 就用到多线程
在单线程中一个线程只能执行一个任务,一个任务处理不完另一个任务就不能开始,这样会影响用户体验,让用户觉得APP 卡顿
现在苹果手机都是多核处理器,这样我们可以把一个任务分成多个步骤,在不要求顺序的情况下,使用多线程既能解决线程阻塞增加用户体验又能充分利用多核处理运行能力
每个应用程序的内部,存在一个或多个执行线程,它同时或在一个几乎同时执行不同的操作
进程与线程
每个系统运行的程序都是一个进程,每个进程里面包含一个或多个线程
线程是一组指令的集合,程序中一个单一的顺序控制流程,是一个程序中,独立运行的程序片段(一个应用程序里面 单一的顺序控制执行的一个任务)
程序运行后,系统会创建一个叫做(main)主线程的线程,所有UI控件都必须运行在主线程中,所以人们也叫它UI线程,如果将所有的任务都放在主线程中,容易造成UI阻塞
多线程:在同一个应用程序内,同时运行多个线程,完成不同的工作
为什么要使用多线程:单线程的应用程序中,代码沿直线执行,只有前面的代码执行完了,才会去执行后面的代码,中间这段时间,实际上就处于等待状态。当用户执行某项操作,比如上传文件,或者下载文件,主线程会执行某项操作,直到上传结束后,主线程才能继续后面的工作,在这段时间内,主线程处于忙碌状态,不会对用户的请求作出任何响应,最直观的感觉就是界面卡死
iOS中有三种多线程策略供开发者使用:NSThread ,NSOperation(基类不可以直接使用 只能使用他的子类),CGD (Grand Central Dispatch)
GCD 苹果推荐 的一种实现 多线程的方式
轻量级 :对系统框架的依赖性的程度
NSThread :是这三种策略里面相对轻量级的,需要自己去管理他的生命周期,以及线程之间的同步,线程共享同一个应用程序的部分内存空间,他们拥有对数据相同的访问权限,所以得协调多个线程对同一数据的访问,常用的做法是在访问之前加锁,这会导致一定的性能开销
下面是NSThread 的一个例子:在下载图片的过程中,点击button时不会因为线程在下载图片而出现卡顿
#import "ViewController.h"
@interface ViewController ()
{
UIImageView *pointView;
}
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor blackColor];
pointView = [[UIImageView alloc]initWithFrame:CGRectMake(0, 0, 100, 100)];
pointView.backgroundColor = [UIColor whiteColor];
pointView.layer.cornerRadius = 100/2;
pointView.layer.masksToBounds = YES;
[self.view addSubview:pointView];
// self.view 添加手势,移动pointView 的中心点位置
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(changePoint:)];
[self.view addGestureRecognizer:tap];
// 点击下载图片 按钮
UIButton *downLoadButton = [UIButton buttonWithType:UIButtonTypeCustom];
downLoadButton.frame = CGRectMake(0, 20, 100, 60);
[downLoadButton setTitle:@"下载图片" forState:UIControlStateNormal];
[downLoadButton addTarget:self action:@selector(downloadImage) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:downLoadButton];
}
- (void)changePoint:(UITapGestureRecognizer *)tap{
NSLog(@"当前线程%@",[NSThread currentThread]);
pointView.center = [tap locationInView:self.view];
}
//开辟线程 去执行另外一个任务 主线程需要的数据 得再次更新 (每一个线程 都是独立的代码片段 当主线程 触发下载任务 开辟另一个线程的时候 主线程会继续执行 子线程 也会独立执行 (主线程不知道子线程什么时候执行完毕))
//执行一个耗时的操作
- (void)downloadImage{
pointView.backgroundColor = [UIColor whiteColor];
// 为了防止 下载任务 阻塞主线程 咱们开辟了一个子线程去执行 耗时的任务
// 使用 alloc init 初始化 需要手动启动线程
NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(downLoadOperation) object:nil];
thread.name = @"下载图片线程";
[thread start];
// detachNewThreadSelector 不需要的手动启动线程
// [NSThread detachNewThreadSelector:@selector(downLoadOperation) toTarget:self withObject:nil];
// 多个线程同时访问一个数据
NSThread *thread2 = [[NSThread alloc]initWithTarget:self selector:@selector(downLoadOperation) object:nil];
thread2.name = @"图片线程";
[thread2 start];
}
- (void)downLoadOperation{
NSLog(@"当前线程::%@",[NSThread currentThread]);
// 模拟下载耗时任务的操作
sleep(5);
// 当操作完毕之后刷新UI 在主线程里面刷新
// 从子线程回到主线程
[self performSelectorOnMainThread:@selector(updateUI) withObject:nil waitUntilDone:YES];
// pointView.backgroundColor = [UIColor yellowColor];
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://b99.photo.store.qq.com/psb?/V13e361D35BV0P/cHUiE3al84faG*lGMQB*I4*WkvSG0dt1iVcDNLa6*NU!/m/dGMAAAAAAAAA&bo=gAJfAwAAAAAFB*o!&rf=photolist"]];
pointView.image = [UIImage imageWithData:data];
}
- (void)updateUI{
NSLog(@"x下载图片线程::%@",[NSThread currentThread]);
pointView.backgroundColor = [UIColor yellowColor];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end