zoukankan      html  css  js  c++  java
  • GCD与block

    GCD技术
    多线程编程的三个技术  NSThread NSOperation GCD
    1.GCD(Grand central Dispatch:宏大的中央调度)
           1) 是用纯C语言实现的.提供了非常多而且强大的函数,可以提高代码的执行效率和多核的利用率
           2) 是在Mac OS X 10.6 雪豹系统  IOS4引入的一种新一代的多线程编程技术
            2.1) 它是由苹果公司为多核的并行运算提出的解决方案
            2.2) 它会自动利用更多的处理器核心
            2.3) 不用关心线程代码,GCD会负责创建线程和调度任务
           3) 核心概念
                任务:执行什么功能,准备执行的代码
                队列:用来存放(调度)任务的.先进先出FIFO,后添加进来的任务在队列末端,但是执行的时机不好说
           4) 使用步骤
                4.1) 先制定任务(确定想做什么事)
                4.2) 把任务添加到适当的队列中即可
             说明:GCD会自动将队列中的任务取出,放到对应的线程中执行
           5) 区分一下名词
            5.1) 同步和异步的区别
             同步和异步是相对于另外一个任务而言的
            同步:在当前线程执行,第一个任务不执行完,第二个任务不会开始
            异步:在另一条线程中执行,不管第一个有没有执行完,都会开始第二个

            5.2) 并发和串行队列的区别
             并发和串行是相对于多个任务而言的
           并发队列:在异步的情况下,多个任务并发执行
           串行队列:多个任务会按照顺序执行
        
            5.3) 并行与并发的区别
              并发说的是多任务,并行说的是多线程
              并行要求并发,并发并不能保证并行(单核)
         */
    1..自定义:串行队列
    dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_SERIAL);
    3.串行队列的异步任务(非常有用)
         特点:会创建新线程(只有一个),任务按照顺序执行
           这是斯坦福大学极力推荐的写法
         优点:不会卡死,任务顺序执行的话方便调试
         缺点:只开一个线程,并发性不强
        /*
    .自定义:并发队列
    1.创建并发队列
         先敲dispatch
         参数1) C的字符串:队列的唯一标识符(域名反写)
         参数2) 队列的类型:SERIAL(NULL)串行  CONCURRENT并发
         */
        dispatch_queue_t queue = dispatch_queue_create("myQueue", DISPATCH_QUEUE_CONCURRENT);
        /*
         2.并发队列的同步任务
         特点:不会创建新线程,任务按照顺序执行(然并卵)
         */
    #pragma mark - 2.系统自带的全局队列
    - (void)gcdDemo3 {
        /*
         1.全局队列
         参数1) 队列的优先级:有四种
         参数2) 标记:为了以后准备的一个参数,填0
         */
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
       
        /*
         2.全局队列的同步任务
         */
        for(int i = 0; i < 100; i ++) {
            dispatch_sync(queue, ^{
                NSLog(@"1:%d----%@",i,[NSThread currentThread]);
            });
        }
       
        /*
         3.全局队列的异步任务
         */
        for(int i= 0; i < 100; i++){
            dispatch_async(queue, ^{
                NSLog(@"2:%d----%@",i,[NSThread currentThread]);
            });
        }
    }
    #pragma mark - 2.系统自带的主队列
    - (void)gcdDemo4 {
        /*
         1.主队列:一般用来UI操作
         */
        dispatch_queue_t queue = dispatch_get_main_queue();
       
        /*
         2.主队列的同步任务:造成一个现象"死锁"
         这个写法不会出现
         for(int i = 0; i < 100; i ++) {
         dispatch_sync(queue, ^{
         NSLog(@"1:%d----%@",i,[NSThread currentThread]);
         });
         }
         */
      
        /*
         3.主队列的异步任务(串行的)
         在主线程中顺序执行
         */
        for(int i= 0; i < 100; i++){
            dispatch_async(queue, ^{
                NSLog(@"2:%d----%@",i,[NSThread currentThread]);
            });
        }

    }
    /*
     小总结
       1.无论什么队列和什么任务,线程的创建和回收不需要程序猿管理,由队列负责
       2.GCD在后端有一个线程池,自己决定block代码块在哪个线程中执行
       3.任务的执行顺序跟队列有关,串行队列不管同步异步都是顺序执行,并发队列在同步时是顺序执行的
     */
    #pragma mark - GCD补充
    #pragma mark 群组
    - (void)gcdDemo5 {
        /*
         例子:下载若干电影(10份),全部下载完以后,弹出警告框
         先下载电影 ---  下载图片  ---  播放
         */
        dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
        dispatch_group_t group = dispatch_group_create();
       
        //向组中和队列中添加任务
        dispatch_group_async(group, queue, ^{
            [NSThread sleepForTimeInterval:10];
            NSLog(@"下载钢铁侠1");
        });
        dispatch_group_async(group, queue, ^{
            [NSThread sleepForTimeInterval:5];
            NSLog(@"下载钢铁侠2");
        });
        dispatch_group_async(group, queue, ^{
            [NSThread sleepForTimeInterval:2];
            NSLog(@"下载钢铁侠3");
        });
        //当组中的所有任务都执行完毕,会发送一个通知
        dispatch_group_notify(group, queue, ^{
            NSLog(@"钢铁侠系列电影下载完毕");
        });
    #pragma mark GCD的内存管理
    - (void)gcdDemo6 {
        /*MRC
         1. 凡是通过create创建出来的queue/group都需要release
         create创建出来的东西引用计数为1,通过dispatch_release变为0,系统释放
         2. 对于系统自带的globalQueue,mainQueue,不需要释放
         3. 如果你创建的group/queue作为全局变量来使用的话,需要dispatch_retain
         */
        dispatch_queue_t queue = dispatch_queue_create("myQueue", NULL);
        dispatch_group_t group = dispatch_group_create();
        /*相关操作*/
        /*使用完毕以后记得释放掉*/
        dispatch_release(queue);
        dispatch_release(group);
       
    }
    #pragma mark GCD的延迟方法
    - (void)gcdDemo7 {
        //[self performSelector:<#(SEL)#> withObject:<#(id)#> afterDelay:<#(NSTimeInterval)#>]
       
        /*
         参数2) 单位是纳秒
         */
        dispatch_time_t myTime = dispatch_time(DISPATCH_TIME_NOW, 2*NSEC_PER_SEC);
        dispatch_after(myTime, dispatch_get_main_queue(), ^{
            NSLog(@"延迟后执行这段代码");
        });
    }
    #pragma mark GCD循环执行某段代码
    - (void)gcdDemo8 {
        /*for循环*/
        /*
         参数1)循环次数
         参数2)队列
         参数3)执行的内容
         */
        dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
        /*
         %zu  --->   无符long 类型
         优点:可以同时遍历多个,效率比较高
         缺点:无序的
         */
        dispatch_apply(100, queue, ^(size_t  index) {
            NSLog(@"------%zu----%@",index,[NSThread currentThread]);
        });
       
    }
     GCD创建单例类

    @implementation People

    static People *instance = nil;
    + (instancetype)sharedPeople {
        /*快捷方式:dispatch_onece*/
        /*
         onceToken作为代码只执行一次的标记
         */
        static dispatch_once_t onceToken;
        /*
         需要且必须执行一次的代码块
         好处:如果多个线程同时调用这个方法,那么该函数会"同步等待",直到代码块执行完毕
         */
      
        dispatch_once(&onceToken, ^{
            instance = [[super allocWithZone:NULL] init];
        });
        return instance;
    }

    + (id)allocWithZone:(struct _NSZone *)zone {
        return [self sharedPeople];
    }

    @end
    block
     block:块.
         在IOS4.0以后引入的新特性.block是Object-C的”特殊对象”,不是NSObject那种对象
         */
       
        /*
         1. 数组遍历/字典:for   for in     block
         */
        NSArray *array1 = @[@"1",@"2",@"3",@"4"];
        /*
         id obj  --->   数组中的每一个对象,类型为id(可以根据实际情况进行修改)
         NSUInteger idx  --->  数组中对象的索引/编号
         BOOL *stop   --->   break
         */
        [array1 enumerateObjectsUsingBlock:^(NSString *obj, NSUInteger idx, BOOL *stop) {
            NSLog(@"%d -- %@",idx,obj);
            if(idx == 1) {
                *stop = YES;
            }
        }];
        /*
         NSEnumerationConcurrent:并发的
         NSEnumerationReverse:反序
         */
        [array1 enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
            NSLog(@"-------   %d -- %@",idx,obj);

        }];
       
       
        /*
         id key --> 字典的key
         id obj --> 字典的key所对应的内容
         */
        NSDictionary *dic = nil;
        [dic enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) {
           
        }];
     /*
         2. UIView动画
         */
        [UIView animateWithDuration:2 animations:^{
            //动画的具体内容:设置控件的终点状态
        }];
       
        [UIView animateWithDuration:2 animations:^{
           
        } completion:^(BOOL finished) {
            //动画完成之后执行的代码写到这里
        }];
       
        //[UIView transitionFromView:<#(UIView *)#> toView:<#(UIView *)#> duration:<#(NSTimeInterval)#> options:<#(UIViewAnimationOptions)#> completion:<#^(BOOL finished)completion#>]
       
       
        /*
         3. 模态
         */
        [self presentViewController:nil animated:YES completion:^{
            //弹出完成后要做的事情
        }];
        [self dismissViewControllerAnimated:YES completion:^{
           //消失之后要做的事情
        }];
       
        /*
         4.发送请求
         */
        [NSURLConnection sendAsynchronousRequest:nil queue:nil completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
           
        }];
       
      5.NSBlockOperation
         */
       
        /*
         6.ASIHttpRequest
         */
        ASIHTTPRequest *request = nil;
        //request.delegate = self;
        [request setCompletionBlock:^{
            //请求完成后的代码
        }];
        [request setFailedBlock:^{
           //请求失败调用的代码
        }];
        [request startAsynchronous];
    }
     /*内存管理
         1.内存主要分为五块
         1.1 栈(区):由编译器自动分配/释放,一般用来存放函数的参数值,局部变量的值等.
            例子:int a = 0;
         1.2 堆(区):一般由程序猿分配/释放.如果说程序员不释放,程序结束时可能由OS回收
            例子:People *p = [[People alloc]init];
         1.3 全局区(静态区):全局变量/静态变量放在这个区域.初始化的全局变量/静态变量放在一个区域,未初始化的全局变量/静态变量放在另一个区域.程序结束后由系统释放
         1.4 文字常量区:常量字符串.程序结束后系统释放
             NSString *name=@"张三";
         1.5 程序代码区:存放函数体的二进制代码
        
         2.block本身的内存管理
            2.1 非ARC
              2.1.1
                 在非ARC下,block默认分配在"栈区".如果离开block方法的作用域,block会被丢弃/释放
              2.1.2
                 NSGlobalBlock(如果块中没有使用外部变量):对于retain,relese,copy无效
                 NSStackBlock(如果块中使用了外部变量):retain,release无效,copy有效,会得到NSMallocBlock
                    陷阱:如果把block添加到数组中,然后再从数组中取出的block已经被释放了,这个block变成了野指针.正确做法是[array addObject:[[block copy]autorelease]]
                 NSMallocBlock(NSStackBlock被copy):支持retain,relese.retain/release可以增加/减少引用计数,但是block的retainCount始终为1.
                 建议:不要对block使用retain操作,不方便管理
            2.2 ARC
         3.block块中对象的内存
         前提:主要是针对copy的block
         */

       
        __block int a = 10;
        void(^block1)() = ^() {
            a = 20;
        };
        block1();
        NSLog(@"%@",[block1 copy]);

        //陷阱
        int b = 20;
        MyBlock block2 = ^() {
            NSLog(@"%d",b);
        };
        block2();
        NSLog(@"block2:%@",block2);
        NSMutableArray *array = [NSMutableArray array];
        [array addObject:[[block2 copy] autorelease]];
       
        MyBlock block3 = array[0];
        block3();
        NSLog(@"block3:%@",block3);
       
        MyBlock block4 = [block3 retain];
        NSLog(@"----%d",[block3 retainCount]);
       
       
       
       
        __block People * localObj = [People new];
        staticObj        = [People new];
        gloabObj          = [People new];
        _propertyObj      = [People new];
       
        NSLog(@"%d--%d--%d--%d====%d",localObj.retainCount,staticObj.retainCount,gloabObj.retainCount,_propertyObj.retainCount,self.retainCount);
       
        /*block块中的对象
         全局变量:不变
         局部变量:通过block copy会+1 (MRC下局部变量一般需要加上__block,防止循环引用,ARC下加__weak)
         static变量:不变
         属性:不变
        
         self本身也会+1
         */
        MyBlock block5 = ^() {
            gloabObj.age = 10;
            staticObj.age = 20;
            _propertyObj.age = 30;
            localObj.age = 40;
        };
        block5();
        [block5 copy];
        NSLog(@"%d--%d--%d--%d====%d",localObj.retainCount,staticObj.retainCount,gloabObj.retainCount,_propertyObj.retainCount,self.retainCount);
       
    }





  • 相关阅读:
    总账数据访问安全性控制(5)
    XML输出中文时,无法用xsl查看(XML文件不能正常显示、中文显示乱码)
    设计抗混叠滤波器的三大指导原则(转载)
    Verilog中变量位宽注意
    学习cordic算法所得(流水线结构、Verilog标准)
    傅里叶分析的理解
    转载:Allegro实用技巧之模块复用
    c语言学习之 辗转相除法求最大公约数
    c语言学习之 正序分解整数
    新博客开张
  • 原文地址:https://www.cnblogs.com/LGX3399577/p/gg.html
Copyright © 2011-2022 走看看