IOS 多线程编程指南_GCD

  1. 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

<script type="text/javascript"> $(function () { $('pre.prettyprint code').each(function () { var lines = $(this).text().split('\n').length; var $numbering = $('<ul/>').addClass('pre-numbering').hide(); $(this).addClass('has-numbering').parent().append($numbering); for (i = 1; i <= lines; i++) { $numbering.append($('<li/>').text(i)); }; $numbering.fadeIn(1700); }); }); </script>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值