一个运行的程序就是一个进程或者叫做一个任务
一个进程至少包含一个线程,线程是程序的执行流
iOS 程序启动时,在创建一个进程的同事,会开始运行一个程序,该程序被称作主线程
主线程是其他线程最终的父线程,所有界面的显示操作必须在主线程进行!!!!
后台线程无法更新UI界面和响应用户点击事件
系统中的每一个进程都是有自己独立的虚拟内存空间,而同一个进程中的多个线程则公用进程的内存空间
每创建一个新的线程,都会消耗一定内存的CPU时间
当多线程对同一个资源出现争夺的时候需要注意线程安全问题
线程的使用不是无节制的 :iOS 主线程的堆栈大小是1M,从第二个线程开始就是512KB,这些数值不能通过编译器开关和线程API函数更改
只有主线程有直接修改UI的能力
一、NSObject多线程方法
1、[NSThread currentThread]; 可以返回当前运行的线程
num = 1 说明是主线程
在任务多线程技术中,均可以使用此方法查看当前的线程情况。
2、新建后台线程,调度任务
[selfperformSelectorInBackground:@selector(bgTask)withObject:nil];
使用performSelectorInBackground是可以修改UI的,不是强烈不建议这样使用。
3、更新界面
使用performSelectorOnMainThread可以在主线程上执行任务。
提示:NSObject对象均可以调用此方法。
4、内存管理
线程任务要包在@autoreleasepool(自动释放池)中,否则容易引起内存泄露,而且非常难发现。
5、总结:使用简单,量级轻,不能控制线程的执行顺序
例如:
@implementation ViewController
- (void)viewDidLoad {
[superviewDidLoad];
UIButton *button1 =[UIButtonbuttonWithType:UIButtonTypeCustom];
button1.backgroundColor =[UIColorredColor];
button1.frame =CGRectMake(50,50, 100,50);
[button1 setTitle:@"耗时操作"forState:UIControlStateNormal];
[button1 addTarget:selfaction:@selector(buttton1)forControlEvents:UIControlEventTouchUpInside];
[self.viewaddSubview:button1];
UIButton *button2 =[UIButtonbuttonWithType:UIButtonTypeCustom];
button2.backgroundColor =[UIColorredColor];
button2.frame =CGRectMake(50,150, 100,50);
[button2 setTitle:@"普通操作"forState:UIControlStateNormal];
[button2 addTarget:selfaction:@selector(button2)forControlEvents:UIControlEventTouchUpInside];
[self.viewaddSubview:button2];
}
-(void)buttton1
{
//后台耗时操作
//performSelectorInBackground会创建一个后台线程,并在该线程中执行调用的方法
// performSelectorInBackground是可以修改UI的但是强烈不建议使用
[selfperformSelectorInBackground:@selector(bgTask)withObject:nil];
}
-(void)button2
{
}
-(void)bgTask
{
@autoreleasepool {
for (int i =0; i < 30000000; i++) {
NSLog(@"%d",i);
}
//在主线程中修改所需要的操作或界面内容;withObject:所需要传递的参数
[selfperformSelectorOnMainThread:@selector(change)withObject:nilwaitUntilDone:YES];
}
}
-(void)change
{
}
二、NThread1、类方法
detachNewThreadSelector直接启动线程,调用选择器方法
2、成员方法
initWithTarget需要使用start方法才能启动实例化出来的线程
优点:简单
缺点:控制线程的生命周期比较困难
控制并发线程数
先后顺序困难
例如:
#import "ViewController.h"
@interface ViewController ()
@PRoperty(nonatomic,strong)NSSet *imageViewSet;
@end
@implementation ViewController
-(void)setUpUI{
//实例化图像视图集合
NSMutableSet *imageSet = [NSMutableSetsetWithCapacity:28];
NSInteger w =self.view.frame.size.width/8;
NSInteger h =self.view.frame.size.height/8;
for (int row =0; row < 7; row++) {
for (int col =0; col < 4; col++) {
//计算图片的位置
NSInteger x = col * w;
NSInteger y = row * h;
UIImageView *imageview =[[UIImageViewalloc]initWithFrame:CGRectMake(x, y, w, h)];
//顺序填充图片
NSInteger num = (row *4 * col) % 17 +1;
NSString *imageName =[NSStringstringWithFormat:@"图片名称%ld",num];
UIImage *image = [UIImageimageNamed:imageName];
[imageview setImage:image];
[self.viewaddSubview:imageview];
[imageSet addObject:imageview];
}
}
self.imageViewSet = imageSet;
//添加按钮
UIButton *button =[UIButtonbuttonWithType:UIButtonTypeRoundedRect];
[button setFrame:CGRectMake(110,self.view.frame.size.height - 80, 100,50)];
[button setTitle:@"刷新图片"forState:UIControlStateNormal];
[button addTarget:selfaction:@selector(click)forControlEvents:UIControlEventTouchUpInside];
[self.viewaddSubview:button];
}
-(void)click
{
[selfthreadLoad];
}
#pragma mark - NSThread方法
-(void)threadLoadImage:(UIImageView *)imageView{
@autoreleasepool {
NSInteger num =arc4random_uniform(17) +1;
NSString *imageName = [NSStringstringWithFormat:@"图片名称%ld",num];
UIImage *image =[UIImageimageNamed:imageName];
//主线程更新UI
[imageView performSelectorOnMainThread:@selector(setImage:)withObject:image waitUntilDone:YES];
}
}
-(void)threadLoad
{
for (UIImageView *imagevin self.imageViewSet) {
//新建线程调用threadLoadImage方法
// [NSThread detachNewThreadSelector:@selector(threadLoadImage:) toTarget:self withObject:imagev];
NSThread *thread = [[NSThreadalloc]initWithTarget:selfselector:@selector(threadLoadImage:)object:imagev];
//启动线程
[thread start];
}
}
- (void)viewDidLoad {
[superviewDidLoad];
[selfsetUpUI];
}
三、NSOperation
1、NSOperation的两个子类NSInvocationOperation,NSBlockOperation例如:
#import "ViewController.h"
@interface ViewController ()
@property(nonatomic,strong)NSSet *imageViewSet;
@property(strong,nonatomic)NSOperationQueue *queue;
@end
@implementation ViewController
-(void)setUpUI{
//实例化图像视图集合
NSMutableSet *imageSet = [NSMutableSetsetWithCapacity:28];
NSInteger w =self.view.frame.size.width/8;
NSInteger h =self.view.frame.size.height/8;
for (int row =0; row < 7; row++) {
for (int col =0; col < 4; col++) {
//计算图片的位置
NSInteger x = col * w;
NSInteger y = row * h;
UIImageView *imageview =[[UIImageViewalloc]initWithFrame:CGRectMake(x, y, w, h)];
//顺序填充图片
NSInteger num = (row *4 * col) % 17 +1;
NSString *imageName =[NSStringstringWithFormat:@"图片名称%ld",num];
UIImage *image = [UIImageimageNamed:imageName];
[imageview setImage:image];
[self.viewaddSubview:imageview];
[imageSet addObject:imageview];
}
}
self.imageViewSet = imageSet;
//添加按钮
UIButton *button =[UIButtonbuttonWithType:UIButtonTypeRoundedRect];
[button setFrame:CGRectMake(110,self.view.frame.size.height - 80, 100,50)];
[button setTitle:@"刷新图片"forState:UIControlStateNormal];
[button addTarget:selfaction:@selector(click)forControlEvents:UIControlEventTouchUpInside];
[self.viewaddSubview:button];
}
-(void)click
{
// [selfoperationLoad];
[selfoperationBlockLoad];
}
#pragma mark - NSOperation方法
-(void)operationBlockLoad
{
for (UIImageView *imagevin self.imageViewSet) {
NSBlockOperation *op = [NSBlockOperationblockOperationWithBlock:^{
[selfoperationLoadImage:imagev];
}];
[self.queueaddOperation:op];
}
}
-(void)operationLoadImage:(UIImageView *)imageView{
@autoreleasepool {
NSInteger num =arc4random_uniform(17) +1;
NSString *imageName = [NSStringstringWithFormat:@"图片名称%ld",num];
UIImage *image =[UIImageimageNamed:imageName];
//主线程更新UI
[[NSOperationQueuemainQueue]addOperationWithBlock:^{
[imageView setImage:image];
}];
}
}
-(void)operationLoad
{
//队列可以设置同时并发线程的数量
[self.queuesetMaxConcurrentOperationCount:3];
for (UIImageView *imagevin self.imageViewSet) {
NSInvocationOperation *op =[[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(operationLoadImage:)object:imagev];
//如果直接调用start,实在主线程队列上运行的,不会开启新的线程
[op start];
//Invocation添加到队列,一添加到队列,就会开启新的线程执行任务
[self.queueaddOperation:op];
}
}
#pragma mark - NSOperation操作之间的顺序
-(void)operationDemo
{
NSBlockOperation *op1 = [NSBlockOperationblockOperationWithBlock:^{
}];
NSBlockOperation *op2 = [NSBlockOperationblockOperationWithBlock:^{
}];
NSBlockOperation *op3 = [NSBlockOperationblockOperationWithBlock:^{
}];
//Dependency依赖依赖关系可以多重依赖
[op2 addDependency:op1];
[op3 addDependency:op2];
[self.queueaddOperation:op3];
[self.queueaddOperation:op1];
[self.queueaddOperation:op2];
}
- (void)viewDidLoad {
[superviewDidLoad];
[selfsetUpUI];
//实例化操作队列
self.queue = [[NSOperationQueuealloc]init];
}
四、GCD#import "ViewController.h"
@interface ViewController ()
@property(nonatomic,strong)NSSet *imageViewSet;
@end
@implementation ViewController
-(void)setUpUI{
//实例化图像视图集合
NSMutableSet *imageSet = [NSMutableSetsetWithCapacity:28];
NSInteger w =self.view.frame.size.width/8;
NSInteger h =self.view.frame.size.height/8;
for (int row =0; row < 7; row++) {
for (int col =0; col < 4; col++) {
//计算图片的位置
NSInteger x = col * w;
NSInteger y = row * h;
UIImageView *imageview =[[UIImageViewalloc]initWithFrame:CGRectMake(x, y, w, h)];
//顺序填充图片
NSInteger num = (row *4 * col) % 17 +1;
NSString *imageName =[NSStringstringWithFormat:@"图片名称%ld",num];
UIImage *image = [UIImageimageNamed:imageName];
[imageview setImage:image];
[self.viewaddSubview:imageview];
[imageSet addObject:imageview];
}
}
self.imageViewSet = imageSet;
//添加按钮
UIButton *button =[UIButtonbuttonWithType:UIButtonTypeRoundedRect];
[button setFrame:CGRectMake(110,self.view.frame.size.height - 80, 100,50)];
[button setTitle:@"刷新图片"forState:UIControlStateNormal];
[button addTarget:selfaction:@selector(click)forControlEvents:UIControlEventTouchUpInside];
[self.viewaddSubview:button];
}
-(void)click
{
[selfgcdLoad];
}
#pragma mark - GCD加载图像
-(void)gcdLoad
{
//派发dispatch异步async执行,并发执行
//PRIORITY优先级,一般选择默认的即可
//获取全局队列
dispatch_queue_t queue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
for (UIImageView *imagevin self.imageViewSet) {
dispatch_async(queue, ^{
NSInteger num =arc4random_uniform(17) +1;
NSString *imageName = [NSStringstringWithFormat:@"图片名称%ld",num];
UIImage *image =[UIImageimageNamed:imageName];
//设置图像,在主线程队列设置UI
dispatch_async(dispatch_get_main_queue(), ^{
[imagev setImage:image];
});
});
}
}
#pragma mark - GCD
-(void)gcdDemo
{
//全局队列中调用异步任务开发时候不用考虑并发线程数量问题
// dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// dispatch_async(queue, ^{
//
// });
// dispatch_async(queue, ^{
//
// });
// dispatch_async(queue, ^{
//
// });
//串行队列,需要创建,不能够get
dispatch_queue_t queue =dispatch_queue_create("myQUeue",DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
});
dispatch_async(queue, ^{
});
dispatch_async(queue, ^{
});
}
- (void)viewDidLoad {
[superviewDidLoad];
[selfsetUpUI];
}
@end
新闻热点
疑难解答