IOS学习——GCD和后台处理

突然接触了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]);
            });    
        }
    });
}


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




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值