多线程的使用是为了避免UI界面的卡死。在子线程中进行耗时间的操作,完成后回到主线程进行UI的显示和刷新。
注意:(1)、在子线程中不要操作UI(不能操作UI)。(2)、子线程里面不要再创建子线程。(3)、主线程只负责UI的刷新和用户的交互。
线程的创建有如下几种方法:
1、同步创建线程
[self sync];
//同步是指所有的任务按次序执行(在一个线程中执行)
//会阻塞UI
-(void)sync
{
[self task1];
[self task2];
[self task3];
}
-(void)task1
{
sleep(1);
NSLog(@"%s,%@",__func__,[NSDate date]);
}
-(void)task2
{
sleep(2);
NSLog(@"%s,%@",__func__,[NSDate date]);
}
-(void)task3
{
sleep(3);
NSLog(@"%s,%@",__func__,[NSDate date]);
}
2、异步 异步创建线程有4+1个c语言的方法
(1)、使用系统的方法
[self systemThread];
//直接调用UI中封装的方法,使用最简单 (在iOS8中好像不支持这些方法了)
-(void)systemThread
{
[self performSelectorInBackground:@selector(task1) withObject:nil];
[self performSelectorInBackground:@selector(task2) withObject:nil];
[self performSelectorInBackground:@selector(task3) withObject:nil];
//
[self performSelectorInBackground:@selector(downLoadAction) withObject:nil];
}
-(void)task1
{
sleep(1);
NSLog(@"%s,%@",__func__,[NSDate date]);
}
-(void)task2
{
sleep(2);
NSLog(@"%s,%@",__func__,[NSDate date]);
}
-(void)task3
{
sleep(3);
NSLog(@"%s,%@",__func__,[NSDate date]);
}
-(void)downLoadAction
{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://image16-c.poco.cn/mypoco/myphoto/20140605/18/17457026820140605181136033_640.jpg?570x300_120"]];
UIImage *img = [UIImage imageWithData:data];
[self performSelectorOnMainThread:@selector(downloadFinished:) withObject:img waitUntilDone:YES];
NSLog(@"download");
}
(2)、NSThread方法
[self nsthread];
//NSThread是OC封装的一套开辟子线程的类
-(void)nsthread
{
[NSThread detachNewThreadSelector:@selector(task1) toTarget:self withObject:nil];
[NSThread detachNewThreadSelector:@selector(task2) toTarget:self withObject:nil];
//或者用下面的方法,但需要手动开启
NSThread *th = [[NSThread alloc]initWithTarget:self selector:@selector(task3) object:nil];
[th start];
}
-(void)task1
{
sleep(1);
NSLog(@"%s,%@",__func__,[NSDate date]);
}
-(void)task2
{
sleep(2);
NSLog(@"%s,%@",__func__,[NSDate date]);
}
-(void)task3
{
sleep(3);
NSLog(@"%s,%@",__func__,[NSDate date]);
}
(3)、NSOperation
[self nsoperation];
-(void)nsoperation
{
//创建多个任务
NSInvocationOperation *opt1 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(task1) object:nil];
NSInvocationOperation *opt2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(task2) object:nil];
NSInvocationOperation *opt3 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(task3) object:nil];
//创建一个线程队列,将任务加入到线程队列中
NSOperationQueue *queue = [[NSOperationQueue alloc]init];
[queue addOperation:opt1];
[queue addOperation:opt2];
[queue addOperation:opt3];
//或者用下面的方面创建线程队列
[queue addOperationWithBlock:^{
sleep(4);
NSLog(@"block:%@",[NSDate date]);
}];
}
-(void)blockOperation{
//NSBlockOperation默认会在当前线程执行。但是 NSBlockOperation 还有一个方法:addExecutionBlock: ,通过这个方法可以给 Operation 添加多个执行 Block。这样operation中的任务会并发执行,它会在主线程和其它多个线程中执行这些任务
//1.创建NSBlockOperation对象
NSBlockOperation *operation=[NSBlockOperation blockOperationWithBlock:^{
NSLog(@"%@",[NSThread currentThread]);
}];
// 添加多个Block
for (NSInteger i=0; i<5; i++) {
[operation addExecutionBlock:^{
NSLog(@"第%ld次:%@",i,[NSThread currentThread]);
}];
}
//开始任务
[operation start];
//NOTE:addExecutionBlock 方法必须在 start() 方法之前执行,否则就会报错:
}
-(void)operationQueue{
// //因为主队列比较特殊,所以会单独有一个类方法来获得主队列。那么通过初始化产生的队列就是其他队列了,因为只有这两种队列,除了主队列,其他队列就不需要名字了。
// //注意:其他队列的任务会在其他线程并行执行
//
// //1.创建一个其他队列
// NSOperationQueue *queue=[[NSOperationQueue alloc] init];
// //2.创建NSBlockOperation对象
// NSBlockOperation *operation=[NSBlockOperation blockOperationWithBlock:^{
// NSLog(@"%@",[NSThread currentThread]);
// }];
// //3.添加多个Block
// for (NSInteger i=0; i<5; i++) {
// [operation addExecutionBlock:^{
// NSLog(@"第%ld次:%@",i,[NSThread currentThread]);
// }];
// }
//设置最大并发数 当设置为1时 就变成串行
queue.maxConcurrentOperationCount=1;
// //4.队列添加到任务
// [queue addOperation:operation];
//NSBlockOperation还有一个非常实用的功能,那就是添加依赖。比如有 3 个任务:A: 从服务器上下载一张图片,B:给这张图片加个水印,C:把图片返回给服务器。这时就可以用到依赖了:
//1.任务一:下载图片
NSBlockOperation *operation1=[NSBlockOperation blockOperationWithBlock:^{
NSLog(@"下载图片 - %@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0];
}];
//2.任务二:打水印
NSBlockOperation *operation2=[NSBlockOperation blockOperationWithBlock:^{
NSLog(@"打水印 - %@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0];
}];
//3.任务三:上传图片
NSBlockOperation *operation3=[NSBlockOperation blockOperationWithBlock:^{
NSLog(@"上传图片 - %@",[NSThread currentThread]);
[NSThread sleepForTimeInterval:1.0];
}];
//4.设置依赖
//任务二依赖任务一
[operation2 addDependency:operation1];
//任务三依赖任务二
[operation3 addDependency:operation2];
//5.创建队列并加入任务
NSOperationQueue *queue=[[NSOperationQueue alloc] init];
//参数二:NSOperationQueue是并行的,所以加入该队列的任务都会在其他线程并行执行,不会阻塞主线程。但如果参数二为YES的话主线程会阻塞,直到queue中的任务执行完成
[queue addOperations:@[operation1,operation2,operation3] waitUntilFinished:NO];
NSLog(@"完成");
}
(4)、gcd 本身是c语言,特点是高效、简洁
[self gcd];
//GCD:大中枢分发,grand centeral dispatch
//它是基于C语言的,基于Blocks
-(void)gcd
{
[self baseQueue];
[self standard];
[self group];
[self barrier];
[self timeAfter];
[self apply];
}
//如果线程队列是同步的,或者加入线程队列的方式是同步加入,执行所有的任务肯定是同步地
//*********
//要想所有的任务都异步执行,必须线程队列是异步队列,同时,加入的任务方式也是异步地
//创建线程队列
//第二个参数表示创建的队列是同步队列还是异步队列
//DISPATCH_QUEUE_SERIAL:同步队列
//DISPATCH_QUEUE_CONCURRENT:异步队列
-(void)baseQueue
{
//#if NO
dispatch_queue_t qt = dispatch_queue_create("com.1000phone", DISPATCH_QUEUE_CONCURRENT);
//async是异步地将一个任务(Blocks)加到队列中
dispatch_async(qt, ^{
[self task1];
});
dispatch_async(qt, ^{
[self task2];
});
dispatch_async(qt, ^{
[self task3];
});
//#endif
#if NO
//线程队列是异步地
dispatch_queue_t qt = dispatch_queue_create("com.1000phone", DISPATCH_QUEUE_CONCURRENT);
//sync是同步地将一个任务(Blocks)加到队列中
dispatch_sync(qt, ^{
[self task1];
});
dispatch_sync(qt, ^{
[self task2];
});
dispatch_sync(qt, ^{
[self task3];
});
#endif
}
//标准用法
//系统自带的线程队列
//系统自带的有5个线程队列
-(void)standard
{
dispatch_async(dispatch_get_global_queue(0, 0), ^{
//子线程的部分
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://image16-c.poco.cn/mypoco/myphoto/20140605/18/17457026820140605181136033_640.jpg?570x300_120"]];
UIImage *img = [UIImage imageWithData:data];
//回到主线程
dispatch_async(dispatch_get_main_queue(), ^{
UIImageView *imgv = [[UIImageView alloc]initWithFrame:CGRectMake(10, 100, 300, 200)];
imgv.image = img;
[self.view addSubview:imgv];
});
});
}
//线程组
-(void)group
{
//线程组的作用,用来监视一组任务的执行完成状态
dispatch_group_t gt = dispatch_group_create();
//创建一个线程队列
dispatch_queue_t qt = dispatch_queue_create("com", DISPATCH_QUEUE_SERIAL);
dispatch_group_async(gt, qt, ^{
[self task1];
});
dispatch_async(dispatch_get_global_queue(0, 0), ^{
[self task2];
});
dispatch_group_async(gt, qt, ^{
[self task3];
});
//所有在线程组中的任务执行完成以后,调用以下方法
dispatch_group_notify(gt, dispatch_get_global_queue(2, 0), ^{
NSLog(@"gt中的所有任务已经执行完成");
});
}
//分组执行
-(void)barrier
{
dispatch_queue_t qt = dispatch_queue_create("com", DISPATCH_QUEUE_CONCURRENT);
dispatch_async(qt, ^{
[self task1];
});
dispatch_async(qt, ^{
[self task2];
});
//中断:有一个前提,线程队列必须是自己创建的:不能用系统自带的线程队列
dispatch_barrier_async(qt, ^{
NSLog(@"++++++++++++++");
});
dispatch_async(qt, ^{
[self task3];
});
dispatch_async(qt, ^{
NSLog(@"---%@",[NSDate date]);
});
}
//延时执行任务 (其和NSTimer的效果一样,不过都说这种方法用起来显得逼格更高一些,哎哎)
-(void)timeAfter
{
//高端
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC * 5ull);
//第一个参数是执行该任务的时间点
//第二个参数是在哪个线程队列中执行
//第三个参数是任务
dispatch_after(time, dispatch_get_main_queue(), ^{
self.view.backgroundColor = [UIColor purpleColor];
});
}
-(void)apply
{
NSMutableArray *_dataArray = [[NSMutableArray alloc]init];
for (int i = 0; i<20000; i++) {
[_dataArray addObject:[NSString stringWithFormat:@"model %d",i]];
}
//处理互相之间不影响的相似操作,和下标的次序没有关系
NSLog(@"--%@",[NSDate date]);
//2015-01-14 14:34:07.251
dispatch_apply(_dataArray.count, dispatch_get_global_queue(0, 0), ^(size_t n) {
NSLog(@"%@",_dataArray[n]);
});
NSLog(@"==%@",[NSDate date]);
//2015-01-14 14:34:14.688
NSLog(@"--%@",[NSDate date]);
for (NSString *str in _dataArray) {
NSLog(@"%@",str);
}
NSLog(@"==%@",[NSDate date]);
//2015-01-14 14:34:23.671
}
哈哈,码完了,那么多总是记不住,用到的时候再回来看看。