• iOS 多线程(NSThread、GCD、NSOperation)


      ios中得多线程技术主要使用3种:NSThreadNSOperationGCD

      一、NSThread: 最轻量级方法,但是不安全需要手动加锁,需要自己管理生命周期

         NSThread的使用方法有2种:   

    // 第一种,需要start
    1
    NSThread *th1 = [[NSThread alloc] initWithTarget:self selector:@selector(btnClick) object:nil]; 2 [th1 setName:@"线程1"]; 3 [th1 start];
    // 第二种
    1
    [NSThread detachNewThreadSelector:@selector(btnClick) toTarget:self withObject:nil];

      因为NSThread使用不安全,我们需要给它加锁(主要的实现代码):

     1 @property (nonatomic,assign) NSInteger fruits;
     2 @property (nonatomic,strong) NSLock *lock;
     3 - (void)viewDidLoad
     4 {
     5     [super viewDidLoad];
     6 
     7     _lock = [[NSLock alloc] init];
     8     _fruits = 50;
     9 }
    10 
    11 - (void)btnClick
    12 {
    13     @synchronized(_lock){ // 加锁
    14         
    15         while (_fruits > 0) {
    16             
    17             NSLog(@"当前线程为:%@ , 剩余票数为:%d",[NSThread currentThread], _fruits);
    18             
    19             _fruits--;
    20         }
    21     }
    22 }

      二、GCD:(Grand Central Dispatch)是一种多核编码技术,用纯C语言编写。

      异步:具备开启线程的功能

      同步:不具备开启线程的功能

      并行队列:多个任务可以同时执行

      串行队列:执行完一个任务后再执行下一个任务

      下面来进行用代码说明:

     1 // 自定义异步方法
     2 - (void)async:(dispatch_queue_t)queue
     3 {
     4     // 异步执行
     5     dispatch_async(queue, ^{
     6         
     7         NSLog(@"im1-%@",[NSThread currentThread]);
     8     });
     9     dispatch_async(queue, ^{
    10         
    11         NSLog(@"im2-%@",[NSThread currentThread]);
    12     });
    13     dispatch_async(queue, ^{
    14         
    15         NSLog(@"im3-%@",[NSThread currentThread]);
    16     });
    17     dispatch_async(queue, ^{
    18         
    19         NSLog(@"im4-%@",[NSThread currentThread]);
    20     });
    21 
    22 }
     1 // 自定义同步方法
     2 - (void)sync:(dispatch_queue_t)queue
     3 {
     4     // 同步执行
     5     dispatch_sync(queue, ^{
     6         
     7         NSLog(@"im1-%@",[NSThread currentThread]);
     8     });
     9     dispatch_sync(queue, ^{
    10         
    11         NSLog(@"im2-%@",[NSThread currentThread]);
    12     });
    13     dispatch_sync(queue, ^{
    14         
    15         NSLog(@"im3-%@",[NSThread currentThread]);
    16     });
    17     dispatch_sync(queue, ^{
    18         
    19         NSLog(@"im4-%@",[NSThread currentThread]);
    20     });
    21 
    22 }

    调用异步执行方法

    1 // 创建一个全局并行队列
    2     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    3     
    4     // 异步执行
    5     [self async:queue];

    最终的结果为:开启了四个线程,并且执行顺序是不定

    1 2015-04-02 16:29:20.438 GCD[4398:1f07] im3-<NSThread: 0x7177ee0>{name = (null), num = 5}
    2 2015-04-02 16:29:20.432 GCD[4398:1303] im1-<NSThread: 0x7177d70>{name = (null), num = 3}
    3 2015-04-02 16:29:20.440 GCD[4398:4307] im4-<NSThread: 0x7178490>{name = (null), num = 6}
    4 2015-04-02 16:29:20.432 GCD[4398:1a03] im2-<NSThread: 0x75429f0>{name = (null), num = 4}
    1 // 创建一个全局串行队列
    2     dispatch_queue_t queue = dispatch_queue_create("wys", NULL);
    3     
    4     // 异步执行
    5     [self async:queue];

    最终的结果为:开启了一个线程,执行顺序为从上往下依次执行

    1 2015-04-02 16:32:19.415 GCD[4442:1303] im1-<NSThread: 0x71631a0>{name = (null), num = 3}
    2 2015-04-02 16:32:19.428 GCD[4442:1303] im2-<NSThread: 0x71631a0>{name = (null), num = 3}
    3 2015-04-02 16:32:19.437 GCD[4442:1303] im3-<NSThread: 0x71631a0>{name = (null), num = 3}
    4 2015-04-02 16:32:19.450 GCD[4442:1303] im4-<NSThread: 0x71631a0>{name = (null), num = 3}

    调用主队列执行方法:

    1 // 创建主队列
    2     dispatch_queue_t queue = dispatch_get_main_queue();
    3     
    4     // 异步执行
    5     [self async:queue];

    最红的结果为:顺序执行并且不开启线程,在主线程中执行

    1 2015-04-02 16:35:45.320 GCD[4484:c07] im1-<NSThread: 0x71560c0>{name = (null), num = 1}
    2 2015-04-02 16:35:45.333 GCD[4484:c07] im2-<NSThread: 0x71560c0>{name = (null), num = 1}
    3 2015-04-02 16:35:45.339 GCD[4484:c07] im3-<NSThread: 0x71560c0>{name = (null), num = 1}
    4 2015-04-02 16:35:45.347 GCD[4484:c07] im4-<NSThread: 0x71560c0>{name = (null), num = 1}
    1 // 创建主队列
    2     dispatch_queue_t queue = dispatch_get_main_queue();
    3     
    4     NSLog(@"start");
    5     
    6     // 同步执行
    7     [self sync:queue];
    8     
    9     NSLog(@"end");

    最终的结果为:执行到start就卡住了,不能往下执行

    1 2015-04-02 16:38:12.856 GCD[4514:c07] start

    调用同步执行方法:

    1 // 创建全局并行队列
    2     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    3     
    4     // 同步执行
    5     [self sync:queue];

    最终的结果为:不开启线程,并且顺序执行,直接主线程执行

    1 2015-04-02 16:41:27.448 GCD[4555:c07] im1-<NSThread: 0x71133c0>{name = (null), num = 1}
    2 2015-04-02 16:41:27.458 GCD[4555:c07] im2-<NSThread: 0x71133c0>{name = (null), num = 1}
    3 2015-04-02 16:41:27.468 GCD[4555:c07] im3-<NSThread: 0x71133c0>{name = (null), num = 1}
    4 2015-04-02 16:41:27.472 GCD[4555:c07] im4-<NSThread: 0x71133c0>{name = (null), num = 1}
    1 // 创建串行队列
    2     dispatch_queue_t queue = dispatch_queue_create("wys", NULL);
    3     
    4     // 同步执行
    5     [self sync:queue];

    最终的结果为:不开启线程,并且顺序执行,直接主线程执行

    1 2015-04-02 16:43:40.609 GCD[4589:c07] im1-<NSThread: 0x713e570>{name = (null), num = 1}
    2 2015-04-02 16:43:40.621 GCD[4589:c07] im2-<NSThread: 0x713e570>{name = (null), num = 1}
    3 2015-04-02 16:43:40.626 GCD[4589:c07] im3-<NSThread: 0x713e570>{name = (null), num = 1}
    4 2015-04-02 16:43:40.634 GCD[4589:c07] im4-<NSThread: 0x713e570>{name = (null), num = 1}

    多线程之间的通信:UI界面的更新一定要在主线程中执行

     1 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 全局并行队列异步执行
     2         
     3         
     4         NSLog(@"全局并行队列异步执行 - %@",[NSThread currentThread]);
     5         
     6         // 获取网络图片数据
     7         NSString *str = @"https://ss0.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3384245408,2851245305&fm=21&gp=0.jpg";
     8         NSURL *url = [NSURL URLWithString:str];
     9         
    10         NSData *data = [NSData dataWithContentsOfURL:url];
    11         
    12         UIImage *image = [UIImage imageWithData:data];
    13         
    14         dispatch_async(dispatch_get_main_queue(), ^{ // 主线程异步执行
    15             
    16             NSLog(@"主线程异步执行 - %@",[NSThread currentThread]);
    17             
    18             // 更新界面
    19             [_im1 setImage:image];
    20         });
    21         
    22     });

    最终的结果为:

    2015-04-03 11:37:08.513 GCD[1095:1303] 全局并行队列异步执行 -<NSThread: 0x754c530>{name = (null), num = 3}
    2015-04-03 11:37:10.657 GCD[1095:c07] 主线程异步执行 -<NSThread: 0x7132c80>{name = (null), num = 1}

    利用多线程来实现延时执行:

    1、利用GCD

     1 double delayInSeconds = 2.0; // 延时时长
     2         dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
     3         dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ // 在主线程中执行
     4             
     5             NSLog(@"%@",[NSThread currentThread]);
     6             
     7             // 更新界面
     8             [_im1 setImage:image];
     9             
    10         });

    2、利用此方法,performSelector为你要调用的方法,withObject为你要传得值,afterDelay为延时时长

    1 [self performSelector:@selector(downLoad) withObject:nil afterDelay:0.5f];

    队列组:

     1 dispatch_group_t group = dispatch_group_create();
     2     dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
     3     
     4     dispatch_group_async(group, queue, ^{
     5         
     6         // 代码1
     7     });
     8     
     9     dispatch_group_async(group, queue, ^{
    10         
    11         // 代码2
    12     });
    13     
    14     dispatch_group_notify(group, queue, ^{
    15         
    16         // 执行完代码1和代码2后,再执行此方法
    17     });

      

      三、NSOperation:基于GCD,能控制最大并发线程数,主要有2个类:NSInvocationOperation和NSBlockOperation

      其步骤为: 创建队列、添加操作、将操作添加到队列

      A、NSInvocationOperation:

     1 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
     2 {
     3     NSOperationQueue *queue = [[NSOperationQueue alloc] init];
     4     
     5     NSInvocationOperation *invo = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(buy) object:nil];
     6     
     7     
     8     [queue addOperation:invo];
     9     
    10 }
    11 
    12 - (void)buy
    13 {
    14     NSLog(@"%@",[NSThread currentThread]);
    15 }

    最后的结果为:开启了一个线程

    1 2015-04-03 14:58:54.060 op1[2631:1e07] <NSThread: 0x71a6de0>{name = (null), num = 3}

      

      B、NSBlockOperation

     1 NSOperationQueue *queue = [[NSOperationQueue alloc] init];
     2     
     3     NSBlockOperation *b1 = [NSBlockOperation blockOperationWithBlock:^{
     4         
     5         NSLog(@"111--%@",[NSThread currentThread]);
     6     }];
     7     NSBlockOperation *b2 = [NSBlockOperation blockOperationWithBlock:^{
     8         
     9         NSLog(@"222--%@",[NSThread currentThread]);
    10     }];
    11     NSBlockOperation *b3 = [NSBlockOperation blockOperationWithBlock:^{
    12         
    13         NSLog(@"333--%@",[NSThread currentThread]);
    14     }];
    15     
    16     
    17     
    18     [queue addOperation:b1];
    19     [queue addOperation:b2];
    20     [queue addOperation:b3];

    最后的结果为:开启了三个线程,自动异步执行

    1 2015-04-03 15:15:59.897 op1[2798:1a03] 111--<NSThread: 0x7544fa0>{name = (null), num = 3}
    2 2015-04-03 15:15:59.901 op1[2798:4307] 222--<NSThread: 0x71506f0>{name = (null), num = 4}
    3 2015-04-03 15:15:59.902 op1[2798:1303] 333--<NSThread: 0x7545e60>{name = (null), num = 5}

    设置依赖:

    1 // 设置依赖 ,b2依赖b1,b3依赖b2,所以执行顺序为,b1->b2->b3
    2     [b2 addDependency:b1];
    3     [b3 addDependency:b2];

    设置队列的最大并发数量

    1 // 设置最大并发(最多同时并发执行3个任务)
    2     queue.maxConcurrentOperationCount = 2;

      C、主队列

     1 NSOperationQueue *queue = [[NSOperationQueue alloc] init];
     2     
     3     [queue addOperationWithBlock:^{
     4         
     5           NSLog(@"-------%@",[NSThread currentThread]);
     6             
     7                // 获取网络图片数据
     8                  NSString *str = @"https://ss0.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3384245408,2851245305&fm=21&gp=0.jpg";
     9                  NSURL *url = [NSURL URLWithString:str];
    10         
    11                  NSData *data = [NSData dataWithContentsOfURL:url];
    12         
    13                  UIImage *image = [UIImage imageWithData:data];
    14         
    15         [[NSOperationQueue mainQueue] addOperationWithBlock:^{ // 主队列
    16                 
    17                  NSLog(@"******%@",[NSThread currentThread]);
    18                 
    19                  // 更新界面
    20                  [_im1 setImage:image];
    21             }];
    22     }];

    最后的结果为:

    1 2015-04-03 15:27:16.077 op1[2916:1c03] -------<NSThread: 0x71613e0>{name = (null), num = 3}
    2 2015-04-03 15:27:17.593 op1[2916:c07] ******<NSThread: 0x7134fa0>{name = (null), num = 1} // 主队列
    欢迎加QQ群交流: iOS: 279096195 React Native: 482205185
  • 相关阅读:
    联想yoga table2 1371f 进入bios 的巧妙方法
    vs开发nodejs api文档生成神器-apidoc
    Android中文乱码彻底解决
    android图片处理方法(不断收集中)
    【Android开发】完美解决Android完全退出程序
    android自动打包方法(ant+proguard+签名)
    Android 访问权限设置记录-存档留着有用!
    [安卓开发]App Widget开发入门指导
    Android蓝牙操作笔记
    android 基于百度地图api开发定位以及获取详细地址
  • 原文地址:https://www.cnblogs.com/GeekStar/p/4387440.html
Copyright © 2020-2023  润新知