IOS多线程之(GCD)
Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法
1.常用的方法dispatch_async 耗时的操作
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 耗时的操作
dispatch_async(dispatch_get_main_queue(), ^{
// 更新界面
});
});
1.Dispatch Group的使用
(void)downloadImages {
并行执行
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 下载第一张图片 NSString *url1 = @"<http://car0.autoimg.cn/upload/spec/9579/u_20120110174805627264.jpg>"; UIImage *image1 = [self imageWithURLString:url1]; // 下载第二张图片 NSString *url2 = @"<http://hiphotos.baidu.com/lvpics/pic/item/3a86813d1fa41768bba16746.jpg>"; UIImage *image2 = [self imageWithURLString:url2]; // 回到主线程显示图片 dispatch_async(dispatch_get_main_queue(), ^{ self.imageView1.image = image1; self.imageView2.image = image2; });
});
}
两张图片的下载过程并不需要按顺序执行,并发执行它们可以提高执行速度
+(void)dispatch{
//得到队列
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(queue, ^{
// 耗时的操作
// 创建一个组
dispatch_group_t group = dispatch_group_create();
// 创建一组任务
dispatch_group_async(group, queue, ^{
NSLog(@"并行执行线程一");
});
// 创建二组任
dispatch_group_async(group, queue, ^{
NSLog(@"并行执行线程二");
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 更新界面
NSLog(@"主线程更新界面");
});
});
}
/// 另一种写法
(void)requestDatasGroup {
// 创建调度组
dispatch_group_t group = dispatch_group_create();
// 创建队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"接口 A 数据请求完成"); dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"接口 B 数据请求完成"); dispatch_group_leave(group);
});
NSLog(@”我是最开始执行的,异步操作里的打印是后执行的”);
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"接口 A 和接口 B 的数据请求都已经完毕!, 开始合并两个接口的数据");
});
}
3、dispatch_barrier_async的使用
顺序执行
dispatch_barrier_async是在前面的任务执行结束后它才执行,而且它后面的任务等它执行完成之后才会执行
例子代码如下
dispatch_queue_t queue = dispatch_queue_create(“gcdtest.rongfzh.yc”, DISPATCH_QUEUE_CONCURRENT);
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:2];
NSLog(@"dispatch_async1");
});
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:4];
NSLog(@"dispatch_async2");
});
dispatch_barrier_async(queue, ^{
NSLog(@"dispatch_barrier_async");
[NSThread sleepForTimeInterval:4];
});
dispatch_async(queue, ^{
[NSThread sleepForTimeInterval:1];
NSLog(@"dispatch_async3");
});
打印结果:
2012-09-25 16:20:33.967 gcdTest[45547:11203] dispatch_async1
2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_async2
2012-09-25 16:20:35.967 gcdTest[45547:11303] dispatch_barrier_async
2012-09-25 16:20:40.970 gcdTest[45547:11303] dispatch_async3
4、dispatch_apply
执行某个代码片段N次。
dispatch_apply(5, globalQ, ^(size_t index) {
// 执行5次
});
5,gcd 延时操作
dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0/延迟执行时间/ * NSEC_PER_SEC));
dispatch_after(delayTime, dispatch_get_main_queue(), ^{
[self reciveNotification:userInfo];
});
其他方法
#pragma mark 第一种解决县城的问题的方法,nsobject提供的方法
-(void)NSObjectThread:(UIButton *)button{
[self performSelectorInBackground:@selector(click:) withObject:button];
//优点:写法特别简单.能快速开辟一个临时线程
//缺点:不能保证线程使用时数据的绝对安全
}
#pragma mark 第二种方式
-(void)NSThreadAction:(UIButton *)button{
//NSThread 本身就是一个线程类,它可以控制线程休眠或者创建..
//当前的主线程
NSLog(@"%@",[NSThread currentThread]);
//主线程休眠3s
// [NSThread sleepForTimeInterval:3];
// NSLog(@”0002112121”);
//如果用创建对象,创建出来的就是新的线程..
NSThread *thread=[[[NSThread alloc] initWithTarget:self selector:@selector(click:) object:nil] autorelease];
//可以给新的线程对象起名
thread.name=@"kitty";
//启动子线程.
[thread start];
//优点:可以直接通过创建的方式来控制线程.
//缺点:什么都需要手动设置,包括名,开始.太麻烦..
}
#pragma mark 第三种 NSOperation 任务
-(void)operationQueue:(UIButton *)button{
//队列和任务一起配合使用解决多线程的问题..
//队列:队列中通过一个线程池来管理所有闲置的线程,这样就可以提高线程的重用率,避免重复的创建线程,,整合资源
//优点:内部不需要关心线程的安全问题,用起来相对简单//
//缺点:效率稍微优点低...
NSOperationQueue *queue=[[NSOperationQueue alloc] init];
//设置最大并发数..
[queue setMaxConcurrentOperationCount:2];
MyOperation *op1=[[MyOperation alloc] init];
MyOperation *op2=[[MyOperation alloc] init];
MyOperation *op3=[[MyOperation alloc] init];
MyOperation *op4=[[MyOperation alloc] init];
MyOperation *op5=[[MyOperation alloc] init];
//把任务加到队列里
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
[queue addOperation:op4];
[queue addOperation:op5];
}
=============
MyOperation 继承于 NSOperation
@implementation MyOperation
-(void)main{
// 要执行的操作。。
}
@end
//利用GCD的dispatch_once的方法实现单利模式
- (instancetype)defaultManager {
staticMusicPlayerViewController *_instance =nil;
staticdispatch_once_tonceToken;
dispatch_once(&onceToken, ^{
_instance = [[selfalloc] init];
});
return_instance;
}
6.后台运行
GCD的另一个用处是可以让程序在后台较长久的运行。在没有使用GCD时,当app被按home键退出后,app仅有最多5秒钟的时候做一些保存或清理资源的工作。但是在使用GCD后,app最多有10分钟的时间在后台长久运行。这个时间可以用来做清理本地缓存,发送统计数据等工作。
// AppDelegate.h文件
@property (assign, nonatomic) UIBackgroundTaskIdentifier backgroundUpdateTask;
// AppDelegate.m文件
- (void)applicationDidEnterBackground:(UIApplication *)application
{
[self beingBackgroundUpdateTask];
// 在这里加上你需要长久运行的代码
[self endBackgroundUpdateTask];
}
- (void)beingBackgroundUpdateTask
{
self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[self endBackgroundUpdateTask];
}];
}
- (void)endBackgroundUpdateTask
{
[[UIApplication sharedApplication] endBackgroundTask: self.backgroundUpdateTask];
self.backgroundUpdateTask = UIBackgroundTaskInvalid;
}
本作品采用《CC 协议》,转载必须注明作者和本文链接