欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

IOS 多线程编程指南_GCD

程序员文章站 2022-04-14 07:49:56
...
  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”);

IOS 多线程编程指南_GCD

由于同步执行会导致线程阻塞,所以做了以下改进

    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]);
        });
}

IOS 多线程编程指南_GCD
这里并发执行第五次打印,但不一定是并发了五个线程,可能是由系统资源确定的

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");

IOS 多线程编程指南_GCD

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];

    });

}

IOS 多线程编程指南_GCD

另外一个例子,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>