码迷,mamicode.com
首页 > 移动开发 > 详细

ios多线程(NSThread、GCD、NSOperation)

时间:2015-04-22 15:55:28      阅读:207      评论:0      收藏:0      [点我收藏+]

标签:ios多线程   gcd   nsoperationqueue   block   nsthread   

    

ios中得多线程技术主要使用3种:NSThread、NSOperation和GCD

  一、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使用不安全,我们需要给它加锁(主要的实现代码):

@property (nonatomic,assign) NSInteger fruits;
@property (nonatomic,strong) NSLock *lock;
- (void)viewDidLoad
{
    [super viewDidLoad];

    _lock = [[NSLock alloc] init];
    _fruits = 50;
}

- (void)btnClick
{
    @synchronized(_lock){ // 加锁
        
        while (_fruits > 0) {
            
            NSLog(@"当前线程为:%@ , 剩余票数为:%d",[NSThread currentThread], _fruits);
            
            _fruits--;
        }
    }
}



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

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

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

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

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

 

  下面来进行用代码说明:

// 自定义异步方法
- (void)async:(dispatch_queue_t)queue
{
    // 异步执行
    dispatch_async(queue, ^{
        
        NSLog(@"im1-%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        
        NSLog(@"im2-%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        
        NSLog(@"im3-%@",[NSThread currentThread]);
    });
    dispatch_async(queue, ^{
        
        NSLog(@"im4-%@",[NSThread currentThread]);
    });

}
// 自定义同步方法
- (void)sync:(dispatch_queue_t)queue
{
    // 同步执行
    dispatch_sync(queue, ^{
        
        NSLog(@"im1-%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        
        NSLog(@"im2-%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        
        NSLog(@"im3-%@",[NSThread currentThread]);
    });
    dispatch_sync(queue, ^{
        
        NSLog(@"im4-%@",[NSThread currentThread]);
    });

}


调用异步执行方法

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

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

2015-04-02 16:29:20.438 GCD[4398:1f07] im3-<NSThread: 0x7177ee0>{name = (null), num = 5}
2015-04-02 16:29:20.432 GCD[4398:1303] im1-<NSThread: 0x7177d70>{name = (null), num = 3}
2015-04-02 16:29:20.440 GCD[4398:4307] im4-<NSThread: 0x7178490>{name = (null), num = 6} 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];

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

2015-04-02 16:32:19.415 GCD[4442:1303] im1-<NSThread: 0x71631a0>{name = (null), num = 3}
2015-04-02 16:32:19.428 GCD[4442:1303] im2-<NSThread: 0x71631a0>{name = (null), num = 3}
2015-04-02 16:32:19.437 GCD[4442:1303] im3-<NSThread: 0x71631a0>{name = (null), num = 3}
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];

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

2015-04-02 16:35:45.320 GCD[4484:c07] im1-<NSThread: 0x71560c0>{name = (null), num = 1}
2015-04-02 16:35:45.333 GCD[4484:c07] im2-<NSThread: 0x71560c0>{name = (null), num = 1}
2015-04-02 16:35:45.339 GCD[4484:c07] im3-<NSThread: 0x71560c0>{name = (null), num = 1}
2015-04-02 16:35:45.347 GCD[4484:c07] im4-<NSThread: 0x71560c0>{name = (null), num = 1}


// 创建主队列

    dispatch_queue_t queue = dispatch_get_main_queue();

    

    NSLog(@"start");

    

    // 同步执行

    [self sync:queue];

    

    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];

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

2015-04-02 16:41:27.448 GCD[4555:c07] im1-<NSThread: 0x71133c0>{name = (null), num = 1}
2015-04-02 16:41:27.458 GCD[4555:c07] im2-<NSThread: 0x71133c0>{name = (null), num = 1}
2015-04-02 16:41:27.468 GCD[4555:c07] im3-<NSThread: 0x71133c0>{name = (null), num = 1}
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];

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

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



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

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 全局并行队列异步执行

        

        

        NSLog(@"全局并行队列异步执行 - %@",[NSThread currentThread]);

        

        // 获取网络图片数据

        NSString *str = @"https://ss0.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3384245408,2851245305&fm=21&gp=0.jpg";

        NSURL *url = [NSURL URLWithString:str];

        

        NSData *data = [NSData dataWithContentsOfURL:url];

        

        UIImage *image = [UIImage imageWithData:data];

        

        dispatch_async(dispatch_get_main_queue(), ^{ // 主线程异步执行

            

            NSLog(@"主线程异步执行 - %@",[NSThread currentThread]);

            

            // 更新界面

            [_im1 setImage:image];

        });

        

    });

最终的结果为:

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

double delayInSeconds = 2.0; // 延时时长

        dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));

        dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ // 在主线程中执行

            

            NSLog(@"%@",[NSThread currentThread]);

            

            // 更新界面

            [_im1 setImage:image];

            

        });

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

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



队列组:

dispatch_group_t group = dispatch_group_create();

    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    

    dispatch_group_async(group, queue, ^{

        

        // 代码1

    });

    

    dispatch_group_async(group, queue, ^{

        

        // 代码2

    });

    

    dispatch_group_notify(group, queue, ^{

        

        // 执行完代码1和代码2后,再执行此方法

    });


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

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

  A、NSInvocationOperation:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event

{

    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    

    NSInvocationOperation *invo = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(buy) object:nil];

    

    

    [queue addOperation:invo];

    

}


- (void)buy

{

    NSLog(@"%@",[NSThread currentThread]);

}

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

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


B、NSBlockOperation

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    

    NSBlockOperation *b1 = [NSBlockOperation blockOperationWithBlock:^{

        

        NSLog(@"111--%@",[NSThread currentThread]);

    }];

    NSBlockOperation *b2 = [NSBlockOperation blockOperationWithBlock:^{

        

        NSLog(@"222--%@",[NSThread currentThread]);

    }];

    NSBlockOperation *b3 = [NSBlockOperation blockOperationWithBlock:^{

        

        NSLog(@"333--%@",[NSThread currentThread]);

    }];

    

    

    

    [queue addOperation:b1];

    [queue addOperation:b2];

    [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、主队列

NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    

    [queue addOperationWithBlock:^{

        

          NSLog(@"-------%@",[NSThread currentThread]);

            

               // 获取网络图片数据

                 NSString *str = @"https://ss0.bdstatic.com/70cFv8Sh_Q1YnxGkpoWK1HF6hhy/it/u=3384245408,2851245305&fm=21&gp=0.jpg";

                 NSURL *url = [NSURL URLWithString:str];

        

                 NSData *data = [NSData dataWithContentsOfURL:url];

        

                 UIImage *image = [UIImage imageWithData:data];

        

        [[NSOperationQueue mainQueue] addOperationWithBlock:^{ // 主队列

                

                 NSLog(@"******%@",[NSThread currentThread]);

                

                 // 更新界面

                 [_im1 setImage:image];

            }];

    }];

最后的结果为:

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} // 主队列


本文出自 “future” 博客,请务必保留此出处http://yuanshui.blog.51cto.com/2097536/1636989

ios多线程(NSThread、GCD、NSOperation)

标签:ios多线程   gcd   nsoperationqueue   block   nsthread   

原文地址:http://yuanshui.blog.51cto.com/2097536/1636989

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!