iOS学习之多线程
2015-07-31 16:48
381 查看
在iOS中提供了4中多线程的方式
以下4中方式:
pthread使用较少
pthread
这是一套通用的多线程api,适用于linux、UNIX、windows 等系统 跨平台技术,可移植 纯c语言
NSThread *current = [NSThread currentThread];
1、创建一个线程id
pthread_t threadId;
pthrad_create(&threadId,NULL,run,NULL);
void *run(void *data)
{
return NULL;
}
NSThread
一个NSThread对象就代表一条线程
使用更加面向对象,可以直接操作线程对象,oc 语言 程序员进行管理 线程的生命周期
主线程相关用法
NSThread *current = [NSThread currentThread];
NSThread *mainThread = [NS]
判断是不是主线程
[NSThread isMainThread];
线程的优先级
NSThread threadPriority
-(BOOL)setThreadPriority:(double);
调度优先级的取值范围是0.0 — 1.0 值越大 优先级越高
1、创建线程
*1
NSThread*thread = [[NSThreadalloc]initWithTarget:self selector:@selector(run:)object:@"aaa"];
//开启线程
[thread
start];
*2 创建后就执行 自动启动
无法对线程进行更详细的设置
[NSThread detachNewThreadSelector:@selector(run:)object:@"aaa"];]
3*//隐式创建
[self
performSelectorInBackground:@selector(run:)withObject:@"aa"];
-(void)run
{
}
线程的生命周期
新建——————》线程对象进入可调度线程池(就绪状态)——————》运行状态(如果cpu调度当前线程)——————》调用sleep方法 当前线程从调度池 ,但是该线程仍然在内存中 —————》当阻塞结束 当前进程进入就绪状态
线程任务执行完毕、异常退出、强制退出 都是 线程进入死亡状态(仍然在内存中)
//阻塞线程
+(void)sleepUntiData:(NSDate:)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
强制停止线程
+(void)exit; 线程进入死亡状态
线程加锁(线程同步)—》多条线程按顺序的执行任务 互斥锁 就是使用了线程同步技术
NSLock *lock = [[NSLock alloc]init];
线程读之前加锁(只能用一把锁)
@synchronized(self){ 加锁
大括号内的代码有线程安全问题代码要进行加锁操作
}大括号结束解锁
线程间通信
两个进行线程间通信的方法
下面方法在主线程中执行settingImage方法
[self performSelectorOnMainThread:@selector(settingImage:) withObject:image waitUntilDone:NO];
下面方法是在onThread指定的线程中执行某个方法
[self performSelector:<#(SEL)#> onThread:<#(NSThread *)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#> modes:<#(NSArray
*)#>]
对ui界面的操作要在主线程中执行,例如以下载图片为例可以使用
下面方法的意思是:在主线程中调用imageView 的 setImage:方法将imageView的image设置为 下载好的image
其中waitUntilDone设置为NO为 调用完这个方法会立即返回
waitUntilDone设置为YES 这个方法会在主线程执行完setImage:方法后返回
[self.imageView performSelector:@selector(setImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:NO];
[self.imageViewperformSelectorOnMainThread:@selector(setImage:)withObject:imagewaitUntilDone:NO];
GCD Grand Central Dispatch 牛逼的中枢调度器
优势:
1、多核的并行运算提出的解决方案
2、会自动利用更多的cpu内核
3、自动关了线程的生命周期(创建线程、调度任务、销毁线程)
4、不需要编写任何线程管理代码 只需要告诉GCD 要执行的任务 GCD 会自动创建队列执行任务
使用:两个步骤
定制任务
添加定制任务到队列中 —》
GCD会自动将队列中的任务取出,放到对应的线程中执行
任务的取出遵循 FIFO 先进先出
//凡是函数名种带有create\copy\new\retain等字眼,都需要在不需要使用这个数据的时候进行release
// GCD的数据类型在ARC环境下不需要再做release
// CF(Core Foundation)的数据类型在ARC环境下还是需要再做release
/**
* 全局并发队列
*/
#define global_queue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)
/**
* 主队列
*/
#define main_queue dispatch_get_main_queue()
基本使用:(同步函数和异步函数———决定了要不要开启新的线程)
1、2个用来执行任务的函数
同步:在当前线程中执行任务 不具备开启新线程的能力
dispatch_sync(<#dispatch_queue_t queue#>, <#^(void)block#>)
异步:在另一条线程中执行 具备了开启新线程的能力
dispatch_async(<#dispatch_queue_t queue#>, <#^(void)block#>)
特殊情况:异步函数的任务添加在主队列中(往主队列中添加一个同步任务), 任务在主线程执行,不会开启新的线程
2、队列
分为两大类(并发和串行————决定了任务的执行方式)
并发队列:可以让多个任务并发同时执行(自动开启多条线程) 在异步函数中执行
串行队列:让任务一个接着一个执行
并发队列:GCD默认已经提供了全局的并发队列供整应用程序使用,不需要手动创建
获取一个全局的默认优先级的并发队列
dispatch_queue_tqueue
=
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0);
添加任务到队列中执行任务
1、
用dispatch_async异步函数往并发队列中添加任务—————》同时开启了3个子线程
- (void)asyncGlobalQueue
{
// 获取一个全局的默认优先级的并发队列
dispatch_queue_t
queue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
// 2.添加任务到队列中执行
dispatch_async(queue, ^{
NSLog(@"----下载图片1-----%@",
[NSThreadcurrentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----下载图片2-----%@",
[NSThreadcurrentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----下载图片3-----%@",
[NSThreadcurrentThread]);
});
//
总结:同时开启了3个线程
}
2、用dispatch_async异步函数 往串行队列中添加任务————————》只开了一个线程执行任务
- (void)asyncSerialQueue
{
// 1.创建串行队列
dispatch_queue_t
queue =
dispatch_queue_create("com.itheima.queue",NULL);
// 2.添加任务到队列中执行
dispatch_async(queue, ^{
NSLog(@"----下载图片1-----%@",
[NSThreadcurrentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----下载图片2-----%@",
[NSThreadcurrentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----下载图片3-----%@",
[NSThreadcurrentThread]);
});
//总结:只开1个线程执行任务
}
3、用dispatch_sync同步函数往并发队列中添加任务—————》不会开启新的线程,并发队列失去了并发的功能
- (void)syncGlobalQueue
{
// 1.获得全局的并发队列
dispatch_queue_t
queue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
// 2.添加任务到队列中执行
dispatch_sync(queue, ^{
NSLog(@"----下载图片1-----%@",
[NSThreadcurrentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----下载图片2-----%@",
[NSThreadcurrentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----下载图片3-----%@",
[NSThreadcurrentThread]);
});
//
总结:不会开启新的线程,并发队列失去了并发的功能
}
4、用dispatch_sync同步函数往串行列中添加任务—————》不会开启新的线程
- (void)syncSerialQueue
{
// 1.创建串行队列(串行队列)
dispatch_queue_t
queue =
dispatch_queue_create("com.itheima.queue",NULL);
// 2.添加任务到队列中执行
dispatch_sync(queue, ^{
NSLog(@"----下载图片1-----%@",
[NSThreadcurrentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----下载图片2-----%@",
[NSThreadcurrentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----下载图片3-----%@",
[NSThreadcurrentThread]);
});
// 3.释放资源
// dispatch_release(queue); // MRC(非ARC)
//
总结:不会开启新的线程
}
5、用dispatch_sync同步函数,在主线程中往主队列中添加任务
: 任务无法往下执行———————>产生死锁(死循环)
- (void)syncMainQueue
{
// 1.获得主队列
dispatch_queue_t
queue =
dispatch_get_main_queue();
// 2.添加任务到队列中执行
(queue, ^{
NSLog(@"----下载图片1-----%@",
[NSThreadcurrentThread]);
});
// dispatch_sync(queue, ^{
// NSLog(@"----下载图片2-----%@",
[NSThread currentThread]);
// });
// dispatch_sync(queue, ^{
// NSLog(@"----下载图片3-----%@",
[NSThread currentThread]);
// });
}
6、
使用dispatch_async异步函数,在主线程中往主队列中添加任务
特殊情况:异步函数的任务添加在主队列中(往主队列中添加一个同步任务), 任务在主线程执行,不会开启新的线程
- (void)asyncMainQueue
{
// 1.获得主队列(串行队列)
dispatch_queue_t
queue =
dispatch_get_main_queue();
// 2.添加任务到队列中执行
dispatch_async(queue, ^{
NSLog(@"----下载图片1-----%@",
[NSThreadcurrentThread]);
});
}
同步函数(sync)
并发队列:不会开启线程
串行队列:不会开启线程
异步函数(async)
并发队列:开启多个线程
串行队列:开启一条线程
使用GCD进行异步图片下载
1、获取全局并发队列
dispatch_queue_tqueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
2、调用异步(同步)函数下载图片
dispatch_async(queue, ^{//开启异步线程下载图片
NSLog(@"当前线程%@",[NSThreadcurrentThread]);
NSURL
*url = [NSURLURLWithString:@"http://www.res.meizu.com/resources/www_image/weixin.jpg"];
NSData
*data = [NSDatadataWithContentsOfURL:url];
UIImage
*image = [UIImageimageWithData:data];
3、回到主队列刷新图片
dispatch_async(dispatch_get_main_queue(),
^{
self.imageView.image=
image;
});
});
GCD的其他用法
1、延迟执行
*1
[self performSelector:@selector(run) withObject:nil afterDelay:2.0];
*2 利用GCD 进行延迟执行(推荐)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// /**
// * 2秒钟后
在队列queue中执行block中的任务
// */
// dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), queue, ^{
//
// });
2、一次性代码 使某一段代码在整个程序运行过程中只执行一次,用于创建单 dispatch_once
static id _instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc]init];
});
3、队列组 当程序需要执行完多个耗时操作后 在执行某个其他操作的时候使用
如:下载两张图片 下载完成后进行拼接显示在imageView上
*1、 创建一个组
dispatch_group_t
group =
dispatch_group_create();
*2、开启一个任务下载图片1
__block
UIImage
*image1 =
nil;
//开启一个任务下载图片1
dispatch_group_async(group,
global_queue, ^{
image1 = [self
imageWithUrl:@"1"];
});
*3 开启一个任务下载图片2
__block
UIImage
*image2 =
nil;
//开启一个任务下载图片2
dispatch_group_async(group,
global_queue, ^{
image2 = [self
imageWithUrl:@"2"];
});
4* 等待group中的所有任务都执行完毕后 在执行其他操作
dispatch_group_notify(group,
main_queue, ^{
//合并图
UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 100), NO, 0.0);
[image1 drawInRect:CGRectMake(0, 0, 100, 100)];
[image2 drawInRect:CGRectMake(100, 0, 100, 100)];
UIImageView *imageView = nil;
imageView.image = UIGraphicsGetImageFromCurrentImageContext();
});
NSOperation
使用NSOperation 的子类 创建任务 NSInvocationOperation 、 NSBlockOperation
1、封装任务
NSInvocationOperation
*opration1 = [[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(download)object:nil];
NSInvocationOperation
*opration2 = [[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(run)object:nil];
NSBlockOperation
*blockOperation = [NSBlockOperationblockOperationWithBlock:^{
NSLog(@"%@——1----",[NSThreadcurrentThread]);
}];
[blockOperationaddExecutionBlock:^{
NSLog(@"%@—2-------",[NSThreadcurrentThread]);
}];
以上有三个操作(opration1、opration2、blockOperation)
4个任务(download、run、%@——1——、%@——2----)
2、创建队列
NSOperationQueue*queue
= [[NSOperationQueuealloc]init];
//最大并发数 同一时间只能做
2件事 控制开线程的个数 queue.maxConcurrentOperationCount=
2;//2---3
//任务在队列中的优先级
/*
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
*/
opration1.queuePriority=
NSOperationQueuePriorityNormal;
操作依赖
//操作依赖 在添加到队列之前
----可以再不同队列间的operation之间添加依赖 不能相互依赖
//opration1依赖
opration2
当opration2执行完毕后才能 执行opration1
[opration1addDependency:opration2];
//操作的监听
//当blockOperation中的操作完成后在当前线程中执行下面操作
blockOperation.completionBlock=
^{
};
//添加到队列中---------》异步执行 多个任务一定是并行操作[queueaddOperation:opration1];
[queueaddOperation:opration2];
[queueaddOperation:blockOperation];
自定义NSOperation
创建属性
/**
* 下载图片的队列
*/
@property(nonatomic,strong)NSOperationQueue
*queue;
/** key:url value:operation对象*/
@property(nonatomic,strong)NSMutableDictionary
*operations;
/** key:url value:image对象*/
@property(nonatomic,strong)NSMutableDictionary
*images;
懒加载
- (NSArray*)apps
{
if
(!_apps) {
NSArray
*dictArray = [NSArrayarrayWithContentsOfFile:[[NSBundlemainBundle]pathForResource:@"apps.plist"ofType:nil]];
NSMutableArray
*appArray = [NSMutableArrayarray];
for
(NSDictionary*dict
in
dictArray) {
HMApp
*app = [HMAppappWithDict:dict];
[appArray
addObject:app];
}
_apps
= appArray;
}
return
_apps;
}
- (NSOperationQueue*)queue
{
if
(!_queue) {
_queue
= [[NSOperationQueuealloc]init];
_queue.maxConcurrentOperationCount=
3;//
最大并发数
== 3
}
return
_queue;
}
- (NSMutableDictionary*)operations
{
if
(!_operations) {
_operations
= [NSMutableDictionarydictionary];
}
return
_operations;
}
- (NSMutableDictionary*)images
{
if
(!_images) {
_images
= [NSMutableDictionarydictionary];
}
return
_images;
}
cell中下载图片的代码
//显示图片
//
保证一个url对应一个HMDownloadOperation
//
保证一个url对应UIImage对象
UIImage
*image =
self.images[app.icon];
if
(image) {
// 内存缓存中有图片
cell.imageView.image=
image;
}
else
{
// 内存缓存中没有图片,得下载
// cell.imageView.image = [UIImage imageNamed:@"57437179_42489b0"];
HMDownloadOperation
*operation =
self.operations[app.icon];
if
(operation) {
//
正在下载
// ...
暂时不需要做其他事
}
else
{
//
没有正在下载
//
创建操作
operation = [[HMDownloadOperationalloc]init];
operation.url=
app.icon;
operation.delegate=
self;
operation.indexPath=
indexPath;
[self.queueaddOperation:operation];//
异步下载
self.operations[app.icon]
= operation;
}
}
#pragma mark - HMDownloadOperationDelegate
- (void)downloadOperation:(HMDownloadOperation*)operation
didFinishDownload:(UIImage*)image
{
// 1.移除执行完毕的操作
[self.operationsremoveObjectForKey:operation.url];
if
(image) {
// 2.将图片放到缓存中(images)
self.images[operation.url]
= image;
// 3.刷新表格
[self.tableViewreloadRowsAtIndexPaths:@[operation.indexPath]withRowAnimation:UITableViewRowAnimationNone];
// 3.将图片写入沙盒
// NSData *data = UIImagePNGRepresentation(image);
// [data writeToFile:@"" atomically:<#(BOOL)#>];
}
}
tableView滚动的时候的操作
- (void)scrollViewWillBeginDragging:(UIScrollView*)scrollView
{
//
开始拖拽
//
暂停队列
[self.queuesetSuspended:YES];
}
- (void)scrollViewWillEndDragging:(UIScrollView*)scrollView
withVelocity:(CGPoint)velocity
targetContentOffset:(inoutCGPoint
*)targetContentOffset
{
[self.queuesetSuspended:NO];
}
自定义NSOperation的代码
HMDownloadOperation.h
@classHMDownloadOperation;
@protocolHMDownloadOperationDelegate
<NSObject>
@optional
- (void)downloadOperation:(HMDownloadOperation*)operation
didFinishDownload:(UIImage*)image;
@end
@interfaceHMDownloadOperation
:
NSOperation
@property(nonatomic,copy)NSString
*url;
@property(nonatomic,strong)NSIndexPath
*indexPath;
@property(nonatomic,weak)id<HMDownloadOperationDelegate>
delegate;
@end
HMDownloadOperation.m
/**
* 在main方法中实现具体操作
*/
- (void)main
{
@autoreleasepool
{
if
(self.isCancelled)return;
NSURL
*downloadUrl = [NSURLURLWithString:self.url];
NSData
*data = [NSDatadataWithContentsOfURL:downloadUrl];//
这行会比较耗时
if
(self.isCancelled)return;
UIImage
*image = [UIImageimageWithData:data];
if
(self.isCancelled)return;
if
([self.delegaterespondsToSelector:@selector(downloadOperation:didFinishDownload:)])
{
dispatch_async(dispatch_get_main_queue(),
^{
//
回到主线程,传递图片数据给代理对象
[self.delegatedownloadOperation:selfdidFinishDownload:image];
});
}
}
以下4中方式:
pthread使用较少
pthread
这是一套通用的多线程api,适用于linux、UNIX、windows 等系统 跨平台技术,可移植 纯c语言
NSThread *current = [NSThread currentThread];
1、创建一个线程id
pthread_t threadId;
pthrad_create(&threadId,NULL,run,NULL);
void *run(void *data)
{
return NULL;
}
NSThread
一个NSThread对象就代表一条线程
使用更加面向对象,可以直接操作线程对象,oc 语言 程序员进行管理 线程的生命周期
主线程相关用法
NSThread *current = [NSThread currentThread];
NSThread *mainThread = [NS]
判断是不是主线程
[NSThread isMainThread];
线程的优先级
NSThread threadPriority
-(BOOL)setThreadPriority:(double);
调度优先级的取值范围是0.0 — 1.0 值越大 优先级越高
1、创建线程
*1
NSThread*thread = [[NSThreadalloc]initWithTarget:self selector:@selector(run:)object:@"aaa"];
//开启线程
[thread
start];
*2 创建后就执行 自动启动
无法对线程进行更详细的设置
[NSThread detachNewThreadSelector:@selector(run:)object:@"aaa"];]
3*//隐式创建
[self
performSelectorInBackground:@selector(run:)withObject:@"aa"];
-(void)run
{
}
线程的生命周期
新建——————》线程对象进入可调度线程池(就绪状态)——————》运行状态(如果cpu调度当前线程)——————》调用sleep方法 当前线程从调度池 ,但是该线程仍然在内存中 —————》当阻塞结束 当前进程进入就绪状态
线程任务执行完毕、异常退出、强制退出 都是 线程进入死亡状态(仍然在内存中)
//阻塞线程
+(void)sleepUntiData:(NSDate:)date;
+ (void)sleepForTimeInterval:(NSTimeInterval)ti;
强制停止线程
+(void)exit; 线程进入死亡状态
线程加锁(线程同步)—》多条线程按顺序的执行任务 互斥锁 就是使用了线程同步技术
NSLock *lock = [[NSLock alloc]init];
线程读之前加锁(只能用一把锁)
@synchronized(self){ 加锁
大括号内的代码有线程安全问题代码要进行加锁操作
}大括号结束解锁
线程间通信
两个进行线程间通信的方法
下面方法在主线程中执行settingImage方法
[self performSelectorOnMainThread:@selector(settingImage:) withObject:image waitUntilDone:NO];
下面方法是在onThread指定的线程中执行某个方法
[self performSelector:<#(SEL)#> onThread:<#(NSThread *)#> withObject:<#(id)#> waitUntilDone:<#(BOOL)#> modes:<#(NSArray
*)#>]
对ui界面的操作要在主线程中执行,例如以下载图片为例可以使用
下面方法的意思是:在主线程中调用imageView 的 setImage:方法将imageView的image设置为 下载好的image
其中waitUntilDone设置为NO为 调用完这个方法会立即返回
waitUntilDone设置为YES 这个方法会在主线程执行完setImage:方法后返回
[self.imageView performSelector:@selector(setImage:) onThread:[NSThread mainThread] withObject:image waitUntilDone:NO];
[self.imageViewperformSelectorOnMainThread:@selector(setImage:)withObject:imagewaitUntilDone:NO];
GCD Grand Central Dispatch 牛逼的中枢调度器
优势:
1、多核的并行运算提出的解决方案
2、会自动利用更多的cpu内核
3、自动关了线程的生命周期(创建线程、调度任务、销毁线程)
4、不需要编写任何线程管理代码 只需要告诉GCD 要执行的任务 GCD 会自动创建队列执行任务
使用:两个步骤
定制任务
添加定制任务到队列中 —》
GCD会自动将队列中的任务取出,放到对应的线程中执行
任务的取出遵循 FIFO 先进先出
//凡是函数名种带有create\copy\new\retain等字眼,都需要在不需要使用这个数据的时候进行release
// GCD的数据类型在ARC环境下不需要再做release
// CF(Core Foundation)的数据类型在ARC环境下还是需要再做release
/**
* 全局并发队列
*/
#define global_queue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)
/**
* 主队列
*/
#define main_queue dispatch_get_main_queue()
基本使用:(同步函数和异步函数———决定了要不要开启新的线程)
1、2个用来执行任务的函数
同步:在当前线程中执行任务 不具备开启新线程的能力
dispatch_sync(<#dispatch_queue_t queue#>, <#^(void)block#>)
异步:在另一条线程中执行 具备了开启新线程的能力
dispatch_async(<#dispatch_queue_t queue#>, <#^(void)block#>)
特殊情况:异步函数的任务添加在主队列中(往主队列中添加一个同步任务), 任务在主线程执行,不会开启新的线程
2、队列
分为两大类(并发和串行————决定了任务的执行方式)
并发队列:可以让多个任务并发同时执行(自动开启多条线程) 在异步函数中执行
串行队列:让任务一个接着一个执行
并发队列:GCD默认已经提供了全局的并发队列供整应用程序使用,不需要手动创建
获取一个全局的默认优先级的并发队列
dispatch_queue_tqueue
=
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
0);
添加任务到队列中执行任务
1、
用dispatch_async异步函数往并发队列中添加任务—————》同时开启了3个子线程
- (void)asyncGlobalQueue
{
// 获取一个全局的默认优先级的并发队列
dispatch_queue_t
queue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
// 2.添加任务到队列中执行
dispatch_async(queue, ^{
NSLog(@"----下载图片1-----%@",
[NSThreadcurrentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----下载图片2-----%@",
[NSThreadcurrentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----下载图片3-----%@",
[NSThreadcurrentThread]);
});
//
总结:同时开启了3个线程
}
2、用dispatch_async异步函数 往串行队列中添加任务————————》只开了一个线程执行任务
- (void)asyncSerialQueue
{
// 1.创建串行队列
dispatch_queue_t
queue =
dispatch_queue_create("com.itheima.queue",NULL);
// 2.添加任务到队列中执行
dispatch_async(queue, ^{
NSLog(@"----下载图片1-----%@",
[NSThreadcurrentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----下载图片2-----%@",
[NSThreadcurrentThread]);
});
dispatch_async(queue, ^{
NSLog(@"----下载图片3-----%@",
[NSThreadcurrentThread]);
});
//总结:只开1个线程执行任务
}
3、用dispatch_sync同步函数往并发队列中添加任务—————》不会开启新的线程,并发队列失去了并发的功能
- (void)syncGlobalQueue
{
// 1.获得全局的并发队列
dispatch_queue_t
queue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
// 2.添加任务到队列中执行
dispatch_sync(queue, ^{
NSLog(@"----下载图片1-----%@",
[NSThreadcurrentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----下载图片2-----%@",
[NSThreadcurrentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----下载图片3-----%@",
[NSThreadcurrentThread]);
});
//
总结:不会开启新的线程,并发队列失去了并发的功能
}
4、用dispatch_sync同步函数往串行列中添加任务—————》不会开启新的线程
- (void)syncSerialQueue
{
// 1.创建串行队列(串行队列)
dispatch_queue_t
queue =
dispatch_queue_create("com.itheima.queue",NULL);
// 2.添加任务到队列中执行
dispatch_sync(queue, ^{
NSLog(@"----下载图片1-----%@",
[NSThreadcurrentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----下载图片2-----%@",
[NSThreadcurrentThread]);
});
dispatch_sync(queue, ^{
NSLog(@"----下载图片3-----%@",
[NSThreadcurrentThread]);
});
// 3.释放资源
// dispatch_release(queue); // MRC(非ARC)
//
总结:不会开启新的线程
}
5、用dispatch_sync同步函数,在主线程中往主队列中添加任务
: 任务无法往下执行———————>产生死锁(死循环)
- (void)syncMainQueue
{
// 1.获得主队列
dispatch_queue_t
queue =
dispatch_get_main_queue();
// 2.添加任务到队列中执行
(queue, ^{
NSLog(@"----下载图片1-----%@",
[NSThreadcurrentThread]);
});
// dispatch_sync(queue, ^{
// NSLog(@"----下载图片2-----%@",
[NSThread currentThread]);
// });
// dispatch_sync(queue, ^{
// NSLog(@"----下载图片3-----%@",
[NSThread currentThread]);
// });
}
6、
使用dispatch_async异步函数,在主线程中往主队列中添加任务
特殊情况:异步函数的任务添加在主队列中(往主队列中添加一个同步任务), 任务在主线程执行,不会开启新的线程
- (void)asyncMainQueue
{
// 1.获得主队列(串行队列)
dispatch_queue_t
queue =
dispatch_get_main_queue();
// 2.添加任务到队列中执行
dispatch_async(queue, ^{
NSLog(@"----下载图片1-----%@",
[NSThreadcurrentThread]);
});
}
同步函数(sync)
并发队列:不会开启线程
串行队列:不会开启线程
异步函数(async)
并发队列:开启多个线程
串行队列:开启一条线程
使用GCD进行异步图片下载
1、获取全局并发队列
dispatch_queue_tqueue =
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
2、调用异步(同步)函数下载图片
dispatch_async(queue, ^{//开启异步线程下载图片
NSLog(@"当前线程%@",[NSThreadcurrentThread]);
NSURL
*url = [NSURLURLWithString:@"http://www.res.meizu.com/resources/www_image/weixin.jpg"];
NSData
*data = [NSDatadataWithContentsOfURL:url];
UIImage
*image = [UIImageimageWithData:data];
3、回到主队列刷新图片
dispatch_async(dispatch_get_main_queue(),
^{
self.imageView.image=
image;
});
});
GCD的其他用法
1、延迟执行
*1
[self performSelector:@selector(run) withObject:nil afterDelay:2.0];
*2 利用GCD 进行延迟执行(推荐)
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// /**
// * 2秒钟后
在队列queue中执行block中的任务
// */
// dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), queue, ^{
//
// });
2、一次性代码 使某一段代码在整个程序运行过程中只执行一次,用于创建单 dispatch_once
static id _instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[self alloc]init];
});
3、队列组 当程序需要执行完多个耗时操作后 在执行某个其他操作的时候使用
如:下载两张图片 下载完成后进行拼接显示在imageView上
*1、 创建一个组
dispatch_group_t
group =
dispatch_group_create();
*2、开启一个任务下载图片1
__block
UIImage
*image1 =
nil;
//开启一个任务下载图片1
dispatch_group_async(group,
global_queue, ^{
image1 = [self
imageWithUrl:@"1"];
});
*3 开启一个任务下载图片2
__block
UIImage
*image2 =
nil;
//开启一个任务下载图片2
dispatch_group_async(group,
global_queue, ^{
image2 = [self
imageWithUrl:@"2"];
});
4* 等待group中的所有任务都执行完毕后 在执行其他操作
dispatch_group_notify(group,
main_queue, ^{
//合并图
UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 100), NO, 0.0);
[image1 drawInRect:CGRectMake(0, 0, 100, 100)];
[image2 drawInRect:CGRectMake(100, 0, 100, 100)];
UIImageView *imageView = nil;
imageView.image = UIGraphicsGetImageFromCurrentImageContext();
});
NSOperation
使用NSOperation 的子类 创建任务 NSInvocationOperation 、 NSBlockOperation
1、封装任务
NSInvocationOperation
*opration1 = [[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(download)object:nil];
NSInvocationOperation
*opration2 = [[NSInvocationOperationalloc]initWithTarget:selfselector:@selector(run)object:nil];
NSBlockOperation
*blockOperation = [NSBlockOperationblockOperationWithBlock:^{
NSLog(@"%@——1----",[NSThreadcurrentThread]);
}];
[blockOperationaddExecutionBlock:^{
NSLog(@"%@—2-------",[NSThreadcurrentThread]);
}];
以上有三个操作(opration1、opration2、blockOperation)
4个任务(download、run、%@——1——、%@——2----)
2、创建队列
NSOperationQueue*queue
= [[NSOperationQueuealloc]init];
//最大并发数 同一时间只能做
2件事 控制开线程的个数 queue.maxConcurrentOperationCount=
2;//2---3
//任务在队列中的优先级
/*
NSOperationQueuePriorityVeryLow = -8L,
NSOperationQueuePriorityLow = -4L,
NSOperationQueuePriorityNormal = 0,
NSOperationQueuePriorityHigh = 4,
NSOperationQueuePriorityVeryHigh = 8
*/
opration1.queuePriority=
NSOperationQueuePriorityNormal;
操作依赖
//操作依赖 在添加到队列之前
----可以再不同队列间的operation之间添加依赖 不能相互依赖
//opration1依赖
opration2
当opration2执行完毕后才能 执行opration1
[opration1addDependency:opration2];
//操作的监听
//当blockOperation中的操作完成后在当前线程中执行下面操作
blockOperation.completionBlock=
^{
};
//添加到队列中---------》异步执行 多个任务一定是并行操作[queueaddOperation:opration1];
[queueaddOperation:opration2];
[queueaddOperation:blockOperation];
自定义NSOperation
创建属性
/**
* 下载图片的队列
*/
@property(nonatomic,strong)NSOperationQueue
*queue;
/** key:url value:operation对象*/
@property(nonatomic,strong)NSMutableDictionary
*operations;
/** key:url value:image对象*/
@property(nonatomic,strong)NSMutableDictionary
*images;
懒加载
- (NSArray*)apps
{
if
(!_apps) {
NSArray
*dictArray = [NSArrayarrayWithContentsOfFile:[[NSBundlemainBundle]pathForResource:@"apps.plist"ofType:nil]];
NSMutableArray
*appArray = [NSMutableArrayarray];
for
(NSDictionary*dict
in
dictArray) {
HMApp
*app = [HMAppappWithDict:dict];
[appArray
addObject:app];
}
_apps
= appArray;
}
return
_apps;
}
- (NSOperationQueue*)queue
{
if
(!_queue) {
_queue
= [[NSOperationQueuealloc]init];
_queue.maxConcurrentOperationCount=
3;//
最大并发数
== 3
}
return
_queue;
}
- (NSMutableDictionary*)operations
{
if
(!_operations) {
_operations
= [NSMutableDictionarydictionary];
}
return
_operations;
}
- (NSMutableDictionary*)images
{
if
(!_images) {
_images
= [NSMutableDictionarydictionary];
}
return
_images;
}
cell中下载图片的代码
//显示图片
//
保证一个url对应一个HMDownloadOperation
//
保证一个url对应UIImage对象
UIImage
*image =
self.images[app.icon];
if
(image) {
// 内存缓存中有图片
cell.imageView.image=
image;
}
else
{
// 内存缓存中没有图片,得下载
// cell.imageView.image = [UIImage imageNamed:@"57437179_42489b0"];
HMDownloadOperation
*operation =
self.operations[app.icon];
if
(operation) {
//
正在下载
// ...
暂时不需要做其他事
}
else
{
//
没有正在下载
//
创建操作
operation = [[HMDownloadOperationalloc]init];
operation.url=
app.icon;
operation.delegate=
self;
operation.indexPath=
indexPath;
[self.queueaddOperation:operation];//
异步下载
self.operations[app.icon]
= operation;
}
}
#pragma mark - HMDownloadOperationDelegate
- (void)downloadOperation:(HMDownloadOperation*)operation
didFinishDownload:(UIImage*)image
{
// 1.移除执行完毕的操作
[self.operationsremoveObjectForKey:operation.url];
if
(image) {
// 2.将图片放到缓存中(images)
self.images[operation.url]
= image;
// 3.刷新表格
[self.tableViewreloadRowsAtIndexPaths:@[operation.indexPath]withRowAnimation:UITableViewRowAnimationNone];
// 3.将图片写入沙盒
// NSData *data = UIImagePNGRepresentation(image);
// [data writeToFile:@"" atomically:<#(BOOL)#>];
}
}
tableView滚动的时候的操作
- (void)scrollViewWillBeginDragging:(UIScrollView*)scrollView
{
//
开始拖拽
//
暂停队列
[self.queuesetSuspended:YES];
}
- (void)scrollViewWillEndDragging:(UIScrollView*)scrollView
withVelocity:(CGPoint)velocity
targetContentOffset:(inoutCGPoint
*)targetContentOffset
{
[self.queuesetSuspended:NO];
}
自定义NSOperation的代码
HMDownloadOperation.h
@classHMDownloadOperation;
@protocolHMDownloadOperationDelegate
<NSObject>
@optional
- (void)downloadOperation:(HMDownloadOperation*)operation
didFinishDownload:(UIImage*)image;
@end
@interfaceHMDownloadOperation
:
NSOperation
@property(nonatomic,copy)NSString
*url;
@property(nonatomic,strong)NSIndexPath
*indexPath;
@property(nonatomic,weak)id<HMDownloadOperationDelegate>
delegate;
@end
HMDownloadOperation.m
/**
* 在main方法中实现具体操作
*/
- (void)main
{
@autoreleasepool
{
if
(self.isCancelled)return;
NSURL
*downloadUrl = [NSURLURLWithString:self.url];
NSData
*data = [NSDatadataWithContentsOfURL:downloadUrl];//
这行会比较耗时
if
(self.isCancelled)return;
UIImage
*image = [UIImageimageWithData:data];
if
(self.isCancelled)return;
if
([self.delegaterespondsToSelector:@selector(downloadOperation:didFinishDownload:)])
{
dispatch_async(dispatch_get_main_queue(),
^{
//
回到主线程,传递图片数据给代理对象
[self.delegatedownloadOperation:selfdidFinishDownload:image];
});
}
}
相关文章推荐
- iOS开发——Xcode基本操作
- 斯坦福大学iOS8公开课笔记01-IOS8结构和MVC模式
- 关于iOS多线程,你看我就够了(已更新)
- iOS学习之KVO、KVC
- [转]关于iOS多线程,你看我就够了
- 关于iOS多线程,你看我就够了
- iOS开发Xcode之:iOS项目的完整重命名方法图文教程
- iOS字体像数与磅的对应关系
- iOS隐藏状态栏
- iOS开发之:iOS单个ViewController支持横屏,其他全竖屏方法
- iOS开发趋势:Native与H5+JS 解决方案
- iOS 浏览器或应用中启动应用
- 制作蒙板(ios)
- ios webview 获取 网页的URL、title和HTML
- iOS开发之:监听音量键
- Alternative access to keyboard height
- IOS 模拟器 在iPhone5和iPhone5s显示不全,不能全屏显示
- GCD ios多线程 runloop
- IOS TableView Cell重用机制
- ios 查看设备的homedirectory