IOS学习——GCD和后台处理

原创 2015年11月19日 21:33:05

突然接触了IOS,来到了一个瑰丽的世界,没想到刚开始工作用到的就是大学唯一一丁点都没有接触的东西,sad!

抒情打住……

OC也是第一次接触,so~~这么一只菜鸟,使用了Apress两本经典作为入门基础:David Mark《精通IOS开发》+Scott Knaster《Objective-C》。这两本书,水果味的,嘿!之前的笔记都记在了“有道”上,记得不详细,所以冒出在博客上写的想法,可能会督促自己认真一些,边学习边记录了。代码的例子用教材中的,然后加上自己的注释和理解。

GCD(grand central dispatch): 底层队列(多线程优化技术)
这项技术到底应该如何理解我还要看更多官方文档才会有自己的理解,这里直接记录学习过程

1.代码块

代码块这个概念在Java中只是在静态块static{  }记得有这么个名词,没想到在OC和swift中运用如此频繁!在Swift中,又称为闭包,不夸张地将,闭包是Swift的一等公民,可以将闭包赋值给变量、传递给方法或者作为调用的返回结果。闭包和等价于OC中的代码块,代码块十分有助于GCD的应用。

<pre name="code" class="objc">//声明一个返回值为空,参数为空的块变量
void (^loggerBlock)(void)
 
__block int a=0;
int b=1;
loggerBlock^{
<span style="white-space:pre">	</span>a=9;
<span style="white-space:pre">	</span>nslog(@"%d",b);
}
//执行
loggerBlock();


注意:块内可以访问在块外定义的变量,如b,但是只能是当块被创建时,这些变量被复制(普通类型int float)或者被保存(指向对象的指针)在块中不可以被更改的同名变量中。就是说,代码块中的b是外面的b复制过来的。
如果要想在块中对块外定义的变量进行写操作,如对a重新赋值,则要把变量a定义为__black int类型!!!
而且这个类型在代码块中被使用后不会被复制和保留。

2.GCD处理

*为了让某个方法在后台运行,只需要
    1、将所有代码包装在一个代码块(Swift称为闭包)中;
    2、将该代码块传递给GCD函数dispatch_async函数。

dispatch_async ( param1 , param2 )
    param1: 一个GCD队列
    param2:代码块

用法:
//1.声明GCD队列    
dispatch_queue_t    globalQueue = dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT/HIGH/LOW);
//2.实现希望后台运行的代码块
dispatch_async ( globalQueue , ^{

    //do something  in 后台线程

     3//得到希望的数据后,回到主线程进行更新
       dispatch_async (dispatch_get_main_queue() , ^{

            do something   in 主线程 
    });

});


下面是教材中的一个例子,这个程序是在在文本框中输入字符串,按下start button,显示字符串的长度,超简单!只是在计算字符串长度的时候用sleep一会儿,所以只用主线程来做的话,页面会一直处于挂起(向Android卡死一样)状态,实际上系统在等着sleep的时间过了,在实际的应用中,用户就会觉得这程序崩了,点击什么的全都无效了所以就用到了GCD来处理这个问题,使程序可以不卡在这里:
-(void)doWork:(id)sender{

    self.resultsTextView.text = @"";
    NSDate *startTime = [NSDate date];
    //后台处理的时候button不可按,并且出现加载动画
    self.startButton.enabled = NO;
    [self.spinner startAnimating];
    
    dispatch_queue_t  globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(globalQueue, ^{
        @try{
        NSString *fetchedData = [self fetchSomethingFromServer];
        NSString *processData = [self processData:fetchedData];
        NSString *firstData  = [self calculateFirstResult:processData];
            NSString *secondData = [self calculateSecondResult:processData];
            NSString *resultData = [NSString stringWithFormat:@"%@ \n %@",firstData,secondData];
        //update in main queue
        dispatch_async(dispatch_get_main_queue(), ^{
           
            self.resultsTextView.text = resultData;
            self.startButton.enabled = YES;
            [self.spinner stopAnimating];
        
        });
        
        NSDate *endTime = [NSDate date];
        NSLog(@"Complete in %f time",[endTime timeIntervalSinceDate:startTime]);
        }@catch (NSException *e){
            NSLog(@"%@",e);
        }
    });
}

如果没有拉回主线程的操作,由于后台想GUI更新数据是不可能的,所以运行到刷新数据的语句后,程序会crash,下面是通过@try @catch 获得的错误信息,主要是通信错误:


接下来我不得不说,下面这个设计太让人舒服了!!!
上面后台处理的解决方案只是为了让程序因为sleepForTimeInterval 而处于挂起模式,但是虽然在底层运行,但我们在时间上还没有进行优化,即:用时还是各方法sleep的总时间, 那么最好的解决方法就是将没有数据干扰的部分并行执行,提高代码的执行速度:这就用到了  分派组 (dispatch group)    可以将需要并行的几块代码放在分派组代码块中,这样各个组内的任务就可以并发执行了!!!
然而,组与组之间处理任务的快慢不同,如果最后的数据更新涉及到所有组,如何判断所有组的任务全部完成了呢?接下来就是真正令我激动的地方——dispatch_group_notify()  
这个函数配合分配组队列使用,指定一个额外的代码块,让这部分代码块在所有组的任务全部执行完毕后再执行

用法:
dispatch_queue_t    globalQueue = dispatch_get_global_queue (DISPATCH_QUEUE_PRIORITY_DEFAULT/HIGH/LOW);
dispatch_async ( globalQueue , ^{

     dispatch_group_t group = dispatch_group_create();
     dispatch_group_async(group , queue,^{
                function1();
    });
     dispatch_group_async(group , queue,^{
                function2();
    });
    dispatch_async_notify(group , queue  , ^{    

         dispatch_async (dispatch_get_main_queue() , ^{

                do something   in 主线程 
            });
    });

});
运用到例子中就是
<pre name="code" class="objc">-(void)doWork2:(id)sender{
    
    self.resultsTextView.text = @"";
    NSDate *startTime = [NSDate date];
    //后台处理的时候button不可按,并且出现加载动画
    self.startButton.enabled = NO;
    self.startButton.alpha = 0.5;
    [self.spinner startAnimating];
    
    dispatch_queue_t  queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
    
            NSString *fetchedData = [self fetchSomethingFromServer];
            NSString *processData = [self processData:fetchedData];
            //NSString *firstData  = [self calculateFirstResult:processData];
            //NSString *secondData = [self calculateSecondResult:processData];
            //NSString *resultData = [NSString stringWithFormat:@"%@ \n %@",firstData,secondData];
            __block NSString *firstData;//need to be assigned in block
            __block NSString *secondData;
            dispatch_group_t group = dispatch_group_create();
            dispatch_group_async(group, queue, ^{
<span style="white-space:pre">		</span>firstData = [self calculateFirstResult:processData];//firstData需在块内进行赋值,所以要声明成__block变量,两个"_"哦
            });
            dispatch_group_async(group, queue, ^{ 
                secondData = [self calculateSecondResult:processData];
            });
            
            dispatch_group_notify(group, queue, ^{
                
                NSString *resultData = [NSString stringWithFormat:@"%@\n%@",firstData,secondData];
                
                //update in main queue
                dispatch_async(dispatch_get_main_queue(), ^{
                
                    self.resultsTextView.text = resultData;
                    self.startButton.enabled = YES;
                    self.startButton.alpha = 1.0;
                    [self.spinner stopAnimating];
                
                });
                
                NSDate *endTime = [NSDate date];
                NSLog(@"Complete in %f time",[endTime timeIntervalSinceDate:startTime]);
            });    
        }
    });
}



写不下去了,明天再补吧,回家睡觉




版权声明:本文为博主原创文章,未经博主允许不得转载。

iOS-多线程编程学习之GCD——串行队列和并发队列(五)

Grand Central Dispatch(GCD)有很多部分构成,例如有很好的语言特性,运行库,还提供了系统的、高效的方式来支持具有多核处理器的iOS和OS X设备进行并发事件处理。   BSD...

iOS多线程学习(1)——GCD

首先我们需要知道的是,什么是多线程? 线程可以理解为我们的处理器在处理我们需要执行的程序或者说代码的一个队列。而多线程就是指我们可以把我们需要处理的事情分开多个队列,让处理器分开去处理,让这些程序或者...
  • Yich_i
  • Yich_i
  • 2015年01月27日 17:56
  • 306

iOS-多线程编程学习之GCD——线程组、延时、计时器等(六)

上一篇文章我们介绍了GCD,以及其队列,同步异步等概念。这次我们将探讨更多GCD的功能,包括线程组(group),栅栏(barrier),单例(once),延时(after),并发迭代(apply)和...

ios开发学习笔记——多进程编程之NSThread/GCD

官网文档:NSThreadClass Reference 一、     基本知识 1、        一个程序会产生一个主线程(MainThread),主线程专门处理UIKit对象的操作 2、   ...

GCD学习之GCD(Grand Central Dispatch)

GCD Grand Central Dispatch(GCD)是异步执行任务的技术之一。一般将应用程序中记述的线程管理用的代码在系统级中实现。开发者只需要定义想要执行的任务并追加到适当的Dispa...
  • yxys01
  • yxys01
  • 2016年05月31日 14:36
  • 372

【读书笔记】iOS-GCD-block-后台运行

当一个app按home键退出的时候,只有最多5秒的时间做一些保存或清理资源的工作。但是调用beginBackgroundTaskWithExpirationHandler方法,可以最多有10分时间在后...

iOS多线程开发—— GCD dispatch_semaphore 信号量

在GCD中提供了一种信号机制,也可以解决资源抢占问题(和同步锁的机制并不一样)。 GCD中信号量是dispatch_semaphore_t类型,支持信号通知和信号等待。每当发送一个信号通知,则信号量 ...
  • xiao__L
  • xiao__L
  • 2016年11月01日 10:37
  • 276

GCD实践——串行队列/并发队列与iOS多线程详解

1.串行队列一次只执行一个线程,按照添加到队列的顺序依次执行; 2.并发队列一次可以执行多个线程,线程的执行没有先后顺序; 3.UI界面所在的线程队列是串行队列。 下面我对上述几个案例进行代码示例...

iOS多线程开发——GCD的使用与多线程开发浅析(二)

对于iOS多线程开发,我们时刻处于学习之中,在看书中,看文档中,项目开发中,都可以去提高自己。最近刚看完了《Objective-C高级编程 iOS与OS X多线程和内存管理》这本书后,对多线程有了更为...

iOS多线程开发——GCD的使用与多线程开发浅析

我在前面的博客中《GCD实践——串行队列/并发队列与IOS多线程详解》中对iOS中的同步异步、串行并行做了较为详细的讲解。在之后的几篇GCD实践的博客中对GCD的使用也有较为详细的实现。但是我们要注意...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:IOS学习——GCD和后台处理
举报原因:
原因补充:

(最多只允许输入30个字)