• iOS:多线程技术GCD的使用


    GCD的使用:

    1.队列的类型
         1.1 主队列:mian queue,主线程队列,负责更行UI的操作。是一个串行的队列。
         1.2 系统默认的并行队列:global queue,按优先级分类。
         1.3 自定义的队列:可以创建串行队列或者是并行的队列
     
    2.任务
         2.1 封装的形式:block方法或C语言的函数
         2.2 添加到队列的方式:同步或异步(只对并行队列有区别)
             例如服务器请求:
             同步:提交请求->等待服务器处理(这个期间客户端浏览器不能干任何事)->处理完毕返回   
             异步:请求通过事件触发->服务器处理(这个期间客户端浏览器仍可以干其他的事)->处理完毕返回
     
    3.特殊使用
         3.1 只执行一次 dispatch_once(dispatch_once_t *predicate, dispatch_block_t block);(多用于单例模式)
         3.2 延时执行    dispatch_after(dispatch_time_t when,dispatch_queue_t  queue,dispatch_block_t block);
         3.3 成组的执行任务       dispatch_group_create(void);
         3.4 创建自定义的队列    dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);
         3.5 创建默认的全局队列 dispatch_get_global_queue(long identifier, unsigned long flags)
         3.6 获取主队列             dispatch_get_main_queue(void)
         3.7 异步执行                dispatch_async(dispatch_queue_t queue, dispatch_block_t block);
         3.8 同步执行              dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);
         3.9 多次执行   dispatch_apply(size_t iterations, dispatch_queue_t queue,void (^block)(size_t));
         …………………等等…………………
     

    4.几个方法参数解释:

    <1>创建自定义的队列    dispatch_queue_create(const char *label, dispatch_queue_attr_t attr);

    const char *label:队列名字                   dispatch_queue_attr_t attr:队列执行方式(串行、并行)

    <2>创建默认的全局队列 dispatch_get_global_queue(long identifier, unsigned long flags)

    long identifier:队列执行的优先级           unsigned long flags:默认为0即可

    <3>多次执行         dispatch_apply(size_t iterations, dispatch_queue_t queue,void (^block)(size_t));

    size_t iterations:执行次数      dispatch_queue_t queue:队列      void (^block)(size_t):block函数块

     
    5.队列方式宏定义(用于创建自定义队列时的参数)

    #define DISPATCH_QUEUE_SERIAL NULL         //串行

    #define DISPATCH_QUEUE_CONCURRENT        //并行

     

    6.队列优先级宏定义(创建全局队列时的参数)

    #define DISPATCH_QUEUE_PRIORITY_HIGH 2

    #define DISPATCH_QUEUE_PRIORITY_DEFAULT 0

    #define DISPATCH_QUEUE_PRIORITY_LOW (-2)

    #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN

     

    7.更能区分

    主队列:专门用来执行主线程的,进行UI的更新操作

    全局队列或自定义队列:用来添加并执行其他的线程,进行数据的操作

     

     具体举例如下:

    例子1:采用不分组的方式,将多线程添加到队列中,然后进行多线程的操作。

    1.准备UI界面布局:拖入一个文本视图控件,并关联相关的类中,同时在类中声明一个票数变量

    @interface ViewController ()
    {
        NSInteger _tickets;
    }
    @property (weak, nonatomic) IBOutlet UITextView *textView;
    @end

    2.设置票数,同时将原来文本视图中默认的数据清空,取消自动布局便于后面添加数据时自动滚动文本视图

     //设置数据和文本视图
     _tickets = 20;
     [self.textView setText:@""];
     self.textView.layoutManager.allowsNonContiguousLayout = NO;

    3.创建全局队列,并设置优先级,设置并行方式

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    4.用GCD创建任务线程,并将线程添加到队列中,采用异步执行方式

    dispatch_async(queue, ^{
            [self GCDSellTicketMethod:@"GCD售票线程-1"];
        });
        
    dispatch_async(queue, ^{
            [self GCDSellTicketMethod:@"GCD售票线程-2"];
        });

    5.定义更新UI的方法

    #pragma mark -更新UI的操作

    -(void)appendTextView:(NSString *)text
    {
        //1.获取原来的数据
        NSMutableString *content = [NSMutableString stringWithString:self.textView.text];
        NSRange range = NSMakeRange(content.length, 2);
    
        //2.追加新的内容
        [content appendString:[NSString stringWithFormat:@"
    %@",text]];
        [self.textView setText:content];
        
        //3.滚动视图
        [self.textView scrollRangeToVisible:range];
    }

    6.定义任务线程的执行方法

    #pragma mark -执行线程的操作

    -(void)GCDSellTicketMethod:(NSString *)name
    {
        while (YES)
        {
            if(_tickets > 0)
            {
                //使用GCD
                dispatch_async(dispatch_get_main_queue(), ^{
                    //更新UI
                    NSString *info = [NSString stringWithFormat:@"总票数:%ld,当前的线程:%@",_tickets,name];
                    [self appendTextView:info];
                    
                    //卖票
                    _tickets--;
                });
                
                //线程休眠
                if([name isEqualToString:@"GCD售票线程-1"])
                {
                    [NSThread sleepForTimeInterval:0.3f];
                }
                else
                {
                    [NSThread sleepForTimeInterval:0.2f];
                }
            }
            else
            {
                //使用GCD更新UI
                dispatch_async(dispatch_get_main_queue(), ^{
                    NSString *info = [NSString stringWithFormat:@"票已经卖完,当前线程:%@",name];
                    [self appendTextView:info];
                });
                
                //退出线程
                break;
            }
        }
    }

    例子2:采用分组的方式,将线程组添加到队列中,然后进行多线程的操作。

    1.准备UI界面布局:拖入一个文本视图控件,并关联相关的类中,同时在类中声明一个票数变量

    @interface ViewController ()
    {
        NSInteger _tickets;
    }
    @property (weak, nonatomic) IBOutlet UITextView *textView;
    @end

    2.设置票数,同时将原来文本视图中默认的数据清空,取消自动布局便于后面添加数据时自动滚动文本视图

     //设置数据和文本视图
     _tickets = 20;
     [self.textView setText:@""];
     self.textView.layoutManager.allowsNonContiguousLayout = NO;

    3.创建一个线程分组

    dispatch_group_t group = dispatch_group_create();

    4.创建自定义的队列,并设置队列执行方式为并行方式

      dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);

    5.用GCD创建任务线程组,并将线程组添加到队列中,采用分组异步执行方式

      dispatch_group_async(group,queue, ^{

          [self GCDSellTicketMethod:@"GCD售票线程-1"];

      });   

      dispatch_group_async(group,queue, ^{

          [self GCDSellTicketMethod:@"GCD售票线程-2"];

      });

    6.等线程组中的所有任务完成后,会接收到通知,更新UI

    dispatch_group_notify(group, queue, ^{
            dispatch_async(dispatch_get_main_queue(), ^{
                NSString *info = [NSString stringWithFormat:@"票已经卖完"];
                [self appendTextView:info];
            });
        });

    7.定义更新UI的方法

    #pragma mark -更新UI的操作

    -(void)appendTextView:(NSString *)text
    {
        //1.获取原来的数据
        NSMutableString *content = [NSMutableString stringWithString:self.textView.text];
        NSRange range = NSMakeRange(content.length, 2);
    
        //2.追加新的内容
        [content appendString:[NSString stringWithFormat:@"
    %@",text]];
        [self.textView setText:content];
        
        //3.滚动视图
        [self.textView scrollRangeToVisible:range];
    }

    8.定义任务线程的执行方法

    #pragma mark -执行线程的操作

    -(void)GCDSellTicketMethod:(NSString *)name
    {
        while (YES)
        {
            if(_tickets > 0)
            {
                //使用GCD
                dispatch_async(dispatch_get_main_queue(), ^{
                    //更新UI
                    NSString *info = [NSString stringWithFormat:@"总票数:%ld,当前的线程:%@",_tickets,name];
                    [self appendTextView:info];
                    
                    //卖票
                    _tickets--;
                });
                
                //线程休眠
                if([name isEqualToString:@"GCD售票线程-1"])
                {
                    [NSThread sleepForTimeInterval:0.3f];
                }
                else
                {
                    [NSThread sleepForTimeInterval:0.2f];
                }
            }
            else
            {   
                //退出线程
                break;
            }
        }
    }

    两种情况的演示结果如下:

     

  • 相关阅读:
    JS 数组
    JS 模拟彩票
    C++ 动态内存
    计算机网络--OSI七层模型
    C++ 异常处理
    C++ 文件和流
    数据库学习教程网站
    数据结构--哈夫曼树
    数据结构--红黑树
    数据结构--伸展树
  • 原文地址:https://www.cnblogs.com/XYQ-208910/p/4859089.html
Copyright © 2020-2023  润新知