IOS 多线程编程指南_GCD
- dispatch_apply
简介:功能:把一项任务提交到队列中多次执行,具体是并行执行还是串行执行由队列本身决定.注意,dispatch_apply不会立刻返回,在执行完毕后才会返回,是同步的调用。
iterations 执行的次数
queue 提交到的队列
block 执行的任务
dispatch_apply(size_t iterations, dispatch_queue_t queue, void (^block)(size_t));
应用举例1>
比如我有一个数组,存储了一系列对象,初始化的时候,这些对象都要调用一次某函数来进行相关的计算。这些计算相互没有影响。这时,我们就可以用dispatch_apply来使用异步队列来初始化.这里把这种情况进行简化
NSMutableArray* muarray = [@[@"hello",@"hellolcg",@"goodbay lms"]mutableCopy];
dispatch_apply(3,dispatch_get_global_queue(0,0),^(size_t time){
NSLog(@"str=%@",muarray[time]);
});
NSLog(@"Dispatch_after in global queue is over");
dispatch_get_global_queue 为全局的并发队列,执行顺序是不确定的,size_t time 的数值必须小于数组数量,否则会越界崩溃
dispath_apply是同步执行的,所以只有数组打印完之后才会执行
NSLog(@”Dispatch_after in global queue is over”);
由于同步执行会导致线程阻塞,所以做了以下改进
dispatch_async(dispatch_get_global_queue(0, 0), ^{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"ssssssssssssss");
});
NSLog(@"Dispatch_after in global queue is over");
});
应用举例2>
- (IBAction)clicked:(id)sender
{
// 控制代码块执行5次
dispatch_apply(5
, dispatch_get_global_queue(0, 0)
// time形参代表当前正在执行第几次
, ^(size_t time)
{
NSLog(@"===执行【%lu】次===%@" , time
, [NSThread currentThread]);
});
}
这里并发执行第五次打印,但不一定是并发了五个线程,可能是由系统资源确定的
2.dispatch_after
功能:延迟一段时间把一项任务提交到队列中执行,返回之后就不能取消
常用来在在主队列上延迟执行一项任务
函数原型
dispatch_after(dispatch_time_t when,
dispatch_queue_t queue,
dispatch_block_t block);
参数
when 过了多久执行的时间间隔
queue 提交到的队列
block 执行的任务
例如:可以利用dispatch_after写一个自己用的Delay函数,delay一段时间在主线程上执行一段代码
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(10 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(@"ssssssssssssss");
});
应用举例1>
比如,当用户的应用不满足某些我们App需要的条件时候(例如,我们的App需要蓝牙打开),然后在APP启动的时候测到蓝牙Off后,应当给用户一个提示。在view载入完成后,延迟给用户一个提示,也可以给这个提示添加一些动画,要比view在载入完成直接显示提示要有好的多。
举例
在viewLoad后,延迟1s,提示一个alertview
class ViewController: UIViewController{
func hwcDelay(delay:Double, closure:()->()) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
override func viewDidLoad(){
super.viewDidLoad()
hwcDelay(1.0){
var alertview = UIAlertView(title:"Dispatch_after",message:"Message",delegate:self,cancelButtonTitle:"OK")
alertview.show()
}
}
override func didReceiveMemoryWarning(){
super.didReceiveMemoryWarning()
}
}
3.dispatch_once
功能:保证在APP运行期间,block中的代码只执行一次
在生成单例的经常使用
当然也可以在多线程环境下,保证一段代码只执行一次。
+ (instancetype)sharedInstance {
static id sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
单例或许你不太明白,下面写一个按钮,无论点击多少次
NSLog输出只会执行一次
- (IBAction)clicked:(id)sender
{
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSLog(@"==执行代码块==");
// 线程暂停3秒
[NSThread sleepForTimeInterval:3];
});
}
4.dispatch_sync()
同步添加操作。他是等待添加进队列里面的操作完成之后再继续执行
- (IBAction)clicked:(id)sender
{
// 以同步方式先后提交2个代码块
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
, ^(void){
for (int i = 0 ; i < 100; i ++)
{
NSLog(@"%@=====%d" , [NSThread currentThread] , i);
[NSThread sleepForTimeInterval:0.1];
}
});
// 必须等第一次提交的代码块执行完成后,dispatch_sync()函数才会返回,
// 程序才会执行到这里,才能提交第二个代码块。
dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
, ^(void){
for (int i = 0 ; i < 100; i ++)
{
NSLog(@"%@-----%d" , [NSThread currentThread] , i);
[NSThread sleepForTimeInterval:0.1];
}
});
}
5.dispatch_async ,异步添加进任务队列,它不会做任何等待
dispatch_queue_t concurrentQueue = dispatch_queue_create("my.concurrent.queue", DISPATCH_QUEUE_CONCURRENT);
NSLog(@"1");
dispatch_async(concurrentQueue, ^(){
NSLog(@"2");
[NSThread sleepForTimeInterval:5];
NSLog(@"3");
});
NSLog(@"4");
6.dispatch_queue_t
GCD队列
dispatch_queue_t disQueue =dispatch_queue_create(“队列1”, 0);
下面展示的是三种获得主线程队列的方式:
NSThread
GCD
NSOperationQueue
-(void)press{
dispatch_queue_t _disQueue=dispatch_queue_create("队列1", 0);
[self startDisPath];
[self runMainByThread];
[self runMainByDisPath];
[self runMainByOpration];
}
-(void)startDisPath
{
dispatch_queue_t global=_disQueue;
dispatch_async(global, ^
{
NSLog(@"=====current==%@", [NSThread currentThread]);
});
}
-(void)runMainByThread
{
[NSThread detachNewThreadSelector:@selector(update01) toTarget:self withObject:nil];
}
-(void)update01
{
while (true) {
static int i=0;
i++;
NSThread*main=[NSThread mainThread];
[self performSelector:@selector(updateMain) onThread:main withObject:nil waitUntilDone:YES];
if (i==1001)
{
[NSThread exit];
}
}
}
-(void)updateMain
{
NSLog(@"在主线程中进行");
}
-(void)runMainByOpration
{
//获得主线程队列
NSOperationQueue*mainQueue=[NSOperationQueue mainQueue];
[mainQueue addOperationWithBlock:^{
NSLog(@"=====current==%@", [NSThread currentThread]);
//在主线程中使用 updateMian
[self updateMain];
}];
}
-(void)runMainByDisPath
{
dispatch_queue_t mainDis=dispatch_get_main_queue();
//
dispatch_async(mainDis, ^{
NSLog(@"=====current==%@", [NSThread currentThread]);
[self updateMain];
});
}
另外一个例子,GCD如何创建一个串行队列和并发队列?
@implementation FKViewController
// 定义2个队列
dispatch_queue_t serialQueue;
dispatch_queue_t concurrentQueue;
- (void)viewDidLoad
{
[super viewDidLoad];
// 创建串行队列
serialQueue = dispatch_queue_create("fkjava.queue", DISPATCH_QUEUE_SERIAL);
// 创建并发队列
concurrentQueue = dispatch_queue_create("fkjava.queue"
, DISPATCH_QUEUE_CONCURRENT);
}
- (IBAction)serial:(id)sender
{
// 依次将2个代码块提交给串行队列
// 必须等到第1个代码块完成后,才能执行第2个代码块。
dispatch_async(serialQueue, ^(void)
{
for (int i = 0 ; i < 100; i ++)
{
NSLog(@"%@=====%d" , [NSThread currentThread] , i);
}
});
dispatch_async(serialQueue, ^(void)
{
for (int i = 0 ; i < 100; i ++)
{
NSLog(@"%@------%d" , [NSThread currentThread] , i);
}
});
}
- (IBAction)concurrent:(id)sender
{
// 依次将2个代码块提交给并发队列
// 两个代码块可以并发执行
dispatch_async(concurrentQueue, ^(void)
{
for (int i = 0 ; i < 100; i ++)
{
NSLog(@"%@=====%d" , [NSThread currentThread] , i);
}
});
dispatch_async(concurrentQueue, ^(void)
{
for (int i = 0 ; i < 100; i ++)
{
NSLog(@"%@------%d" , [NSThread currentThread] , i);
}
});
}
@end
参考来源:
http://write.blog.csdn.net/mdeditor
关于介绍GCD一篇比较好的博客(文顶顶)
http://www.cnblogs.com/wendingding/p/3806821.html
上一篇: iOS GCD