• iOS中的线程的总结和GCD


      进程和线程是操作系统中的概念,以我的理解呢 一个CPU就好比是一个工厂,而一个工厂里面可以有多个车间,一个进程就好比是一个工厂中的一个车间,而线程就好比是车间里的工人,也就是说一个进程中可以有多个线程。

      那么在iOS开发过程中,怎么样开始一个线程呢,有以下三种方法:

      1.performSelectorInBackground

      例如:开启一个线程的方法

      - (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg

      2.使用NSThread 静态方法 (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument; 

    也就是直接创建了一个线程,SEL参数指是这个线程需要执行的作务, 使用这个方法的话,线程直接启动

      例如:[NSThread detachNewThreadSelector:@selector(doThing) toTarget:self  withObject:nil];

      3.创建NSThread 的对象, 然后调用start来启动线程 

      - (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument 

      例如:NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(doThing) object:nil];

           thread.name = @"QingYun";

         //启动线程

         [thread start];

      知道了怎么创建一个线程,那么怎么样创建一个多线程呢?

      有两种方法可以实现多线程

      1. 先创建NSOperation 子类对象, 然后使用NSOperationQueue来实现多线程 

      使用- (id)initWithTarget:(id)target selector:(SEL)sel object:(id)arg;

      例如:

      

       //创建一个多线程的队列
    
       NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    
       //创建一个操作对象,这个操作对象定义了多线程需要执行作务
    
       NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doThing) object:nil];
       //将操作对象放到这个队列里,这样线程就可以直接启动
        [queue addOperation:operation];

      

    2.创建NSBlockOperation对象然后使用NSOperationQueue来实现多线程

        

        NSOperationQueue *queue = [[NSOperationQueuealloc] init];

        NSBlockOperation *operation = [NSBlockOperationblockOperationWithBlock:^{

            NSLog(@"do thing....");

            //当前线程休眠10

            [NSThreadsleepForTimeInterval:10];

          NSThread *thread = [NSThread currentThread];//查看当前的进程

            if ([thread isMainThread]) {//判断当前进程是不是主线程

                NSLog(@"main thread");

            }else

            {

                NSLog(@"peer thread");

            }

             NSLog(@"DONE.%@",thread.name);

        }];

        [queue addOperation:operation];

      单线程和多线程的使用大家都知道了,我们接下来说一个更好用技术,GCD ,什么是GCD呢?

      Grand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。该方法在Mac OS X 10.6雪豹中首次推出,并随后被引入到了iOS4.0中。GCD是一个替代诸如NSThread, NSOperationQueue, NSInvocationOperation等技术的很高效和强大的技术,它看起来象就其它语言的闭包(Closure)一样,但苹果把它叫做blocks。

      让我们来看一个编程场景。在iphone上做一个下载网页的功能,该功能非常简单,就是在iphone上放置一个按钮,点击该按钮时,显示一个转动的圆圈,表示正在进行下载,下载完成之后,将内容加载到界面上的一个文本控件中。如果没有提示会给用户带来不好的用户体验。

      

      GCD就是用来解决这个问题的,dispatch是使用C风格的代码写的。

      //创建一个队列 
    dispatch_queue_t queque
    = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
       dispatch_async (queque,
    ^{ NSLog(@"do thing...."); //当前线程休眠10秒 [NSThread sleepForTimeInterval:5]; NSThread *thread = [NSThread currentThread]; if ([thread isMainThread]) { NSLog(@"main thread"); }else { NSLog(@"peer1 thread"); } NSLog(@"DONE.%@",thread.name); }); dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{ NSLog(@"do another thing...."); //当前线程休眠10秒 [NSThread sleepForTimeInterval:5]; NSThread *thread = [NSThread currentThread]; if ([thread isMainThread]) { NSLog(@"main thread"); }else { NSLog(@"peer2 thread"); } NSLog(@"DONE.%@",thread.name); });

      其中,dispatch_get_global_queue(dispatch_queue_priority_t priority,unsignedlong flags);中第一个参数的优先级有如下几种:

       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

      上述例子中使用的是dispatch_async(dispatch_queue_t queue, dispatch_block_t block),这个方法是异部的,即相当于使用的多线程,多线程的优先级是在程序最开始优先级级别高的会先调用,因为这两个线程都是子线程,有使用的过程中会存在竟争状态。 ,还有一个方法是dispatch_sync(dispatch_queue_t queue, dispatch_block_t block),这个方法模拟的是单线程。

     

    程序运行的结果是:

    2014-05-15 16:29:54.070 ThreadSample[4465:60b] BUTTON ACTION

    2014-05-15 16:29:54.070 ThreadSample[4465:1303] do thing....

    2014-05-15 16:29:54.070 ThreadSample[4465:3903] do another thing....

    2014-05-15 16:29:59.073 ThreadSample[4465:1303] peer1 thread

    2014-05-15 16:29:59.074 ThreadSample[4465:1303] DONE.

    2014-05-15 16:29:59.073 ThreadSample[4465:3903] peer2 thread

    2014-05-15 16:29:59.075 ThreadSample[4465:3903] DONE.

      下面来模拟一个从服务器上获取数据的例子:


    #import "QYViewController.h"
    @interface
    QYViewController ()
    //在函数中定义的全局变量 @property (weak, nonatomic) IBOutlet UIButton
    *buttonStart; @property (weak, nonatomic) IBOutlet UITextView *resultTextView; @property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicator; @end
    @implementation QYViewController

    - (void)viewDidLoad

    {

    [superviewDidLoad];

    }

    - (void)didReceiveMemoryWarning

    {

        [superdidReceiveMemoryWarning];

        // Dispose of any resources that can be recreated

    }

    @end

      然后在@implementation 和@end之间添加模拟的方法:如下所示:

    //模拟从服务器上获取数据
    - (NSString*)fetchSomeThingFromServer
    {
        [NSThread sleepForTimeInterval:1];
        return @"Hi there";
    }
    
    //模拟处理从服务器上取下的数据的过程
    - (NSString*)processData:(NSString*)data
    {
        [NSThread sleepForTimeInterval:2];
    //    主功能是:如果取下的数据是大不写, 全部转换成大写
        return [data uppercaseString];
    }
    
    //模拟第一次处理从服务器获取的数据
    - (NSString*)calculateFirstResult:(NSString*)data
    {
        [NSThread sleepForTimeInterval:3];
        return [NSString stringWithFormat:@"Number of chars: %d",data.length];
    }
    
    //模拟第二次处理从服务器取下的值
    - (NSString*)calculateSecondResult:(NSString*)data
    {
        [NSThread sleepForTimeInterval:4];
    //    将字符串data中的所有大写的E字母转换成小写
        return [data stringByReplacingOccurrencesOfString:@"E" withString:@"e"];
    }

      添加- (IBAction)doSomeWork:(id)sender {


    // 计算一下从开始工作, 到结束一共花费了多少CPU的时间 NSDate *startTime = [NSDate date];
    //当获取数据的时候将按钮设置为不可点击 self.buttonStart.enabled
    = NO; self.buttonStart.alpha = 0.5;
    //添加一个风火轮,当获取数据的时候开始转动 [self.activityIndicator startAnimating]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,
    0), ^{

        //以下两个程序的执行顺序不能改变,所以不能使用分组 NSString
    *fetchData = [self fetchSomeThingFromServer]; NSString *processData = [self processData:fetchData]; // NSString *firstResult = [self calculateFirstResult:processData]; // NSString *secondResult = [self calculateSecondResult:processData]; // 关于block块的变量作用范围
    //     block块中可以使用block块外的变量,但是它使用的时候是把block外的变量拷贝过来当做常量使用,若不想当做就是使用应该在变量定义的时候前面加上__block  
        __block NSString *firstResult; __block NSString *secondResult; // 创建一个group dispatch_group_t group = dispatch_group_create(); dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ firstResult = [self calculateFirstResult:processData]; NSLog(@"%@",firstResult); }); dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ secondResult = [self calculateSecondResult:processData]; NSLog(@"%@",secondResult); }); // 根据计算后的结果, 拼接成新的包含换行的字符串 dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSString *resultSummary = [NSString stringWithFormat:@"First:[%@] Second:[%@]",firstResult,secondResult]; // 将计算好的结果的字符串放在我们的界面上。
          //这是需要注意的是所有的关于视图的操作均会在主线程上操作
              dispatch_sync(dispatch_get_main_queue(), ^{ self.resultTextView.text = resultSummary; self.buttonStart.enabled = YES; self.buttonStart.alpha = 1.0f; [self.activityIndicator stopAnimating]; });
          //结束时间必须放在第一个异步的数据块里面,因为使用的异步操作,就相当于是多线程,如果放在外面会直接走下一步,计算不出准确的时间 NSDate
    *endTime = [NSDate date]; NSLog(@"Completed in %f seconds",[endTime timeIntervalSinceDate:startTime]); }); }); }

      模拟的结果如下:

            

     

  • 相关阅读:
    xml和json笔记
    Ajax开发技术介绍与实战练习
    MATLAB学习(4)——min
    MATLAB学习(2)——zeros
    MATLAB学习(1)——ordfilt2
    vim的基本命令
    VS2015 闪退问题
    Error (10028): Can't resolve multiple constant drivers for net "mydata[14]" at sd_read.v(207)
    自动识别设备
    Internal Error: Sub-system: CUT, File: /quartus/db/cut/cut_post_syn_util.cpp, Line: 709 name_to_atom_map[iname] == 0
  • 原文地址:https://www.cnblogs.com/xinianhao/p/3730418.html
Copyright © 2020-2023  润新知