IOS开发之多线程

IOS开发之多线程

1. 多线程简述

  什么是多线程? 解决的问题?

    多线程是指,编程中在主线程之外开辟的新线程,用于处理一些耗时的、并发的任务。使用多线程可以避免主线程的阻塞,

      也对一个线程不容易实现的任务提供了思路。在多线程的知识中也涉及队列,锁等概念。

    在这里科普一下队列的概念,队列:是管理线程的,相当于线程池,能管理线程什么时候执行。队列分为串行队列和并行队列。

    串行队列:队列中的线程按顺序执行(不会同时执行)

    并行队列:队列中的线程会并发执行,可能会有一个疑问,队列不是先进先出吗,如果后面的任务执行完了,怎么出去的了。

          这里需要强调下,任务执行完毕了,不一定出队列。只有前面的任务执行完了,才会出队列。

     

    (1)pthred多线程(POSIX标准),用在类unix系统上。

    (2)NSThread   是对pthred面相对象封装

    (3)NSOperation/NSOperationQueue   是使用GCD实现的一套Objective-C的API

    (4)GCD(Grand Central Dispatch)   是基于C语言的底层API

      使用较多,因为:1.支持多核心 2.c和block接口,易使用 3.功能强

2.NSThread

  2.1线程的创建 线程的控制和通信

技术分享
    (1)创建线程
    [self createThread];
    
    (4) 线程的控制和通信
    实例: A线程执行到10得时候让B线程结束

#pragma mark -- (1)创建线程
#pragma mark -- (4) 线程的控制和通信
-(void)createThread{
    //线程
    
    //顺序执行(串行执行)
    //[self taskA];
    //[self taskB];

    //并行执行(多个任务同时执行)
    //创建新的线程(第一种方式)---对应一个方法
    //注意:创建之后不会立即执行,需要start
    NSThread *thread1 = [[NSThread alloc]initWithTarget:self selector:@selector(taskA) object:nil];
    [thread1 start];
    
    //创建新的线程(方式2)
    //创建后会立即执行
    [NSThread detachNewThreadSelector:@selector(taskB:) toTarget:self withObject:thread1];
    
    
    
}

-(void)taskA{
    for (int i = 0; i < 20 ; i ++) {
        NSLog(@"A = %d",i);
        
        //每一次检测是否停止
        if ([NSThread currentThread].isCancelled) {
            //退出当前线程
            [NSThread exit];
        }
        
        //线程每次休眠时间为0.25s
        [NSThread sleepForTimeInterval:0.25];
    }
}

-(void)taskB:(NSThread *)thread{
    for (int i = 0; i < 20 ; i ++) {
        NSLog(@"B = %d",i);
        if ( i == 10) {
            //停止线程,发送cancle消息
            [thread cancel];
        }
        [NSThread sleepForTimeInterval:0.25];

    }
}
创建线程、线程的控制和通信

  2.2为什么使用多线程,解决什么样的问题

技术分享
#pragma mark -- (2)为什么使用多线程,解决什么样的问题
-(void)whyUseThread{

    //本质: 多线程主要解决执行耗时任务出现UI界面阻塞的问题
    //      有时候为了同时执行多个任务(类似迅雷)
    //场景: 大麦网 -- 下载数据(耗时10s)
    //      图片(耗时5s)
    //      迅雷看看,加载1G视频文件
    //      数据库中加载1w条数据
    
    //演示
    UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem];
    button.frame = CGRectMake(0, 20, 320, 40);
    [button setTitle:@"耗时任务" forState:UIControlStateNormal];
    [button addTarget:self action:@selector(startTask) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:button];
}
-(void)startTask{
    //http://10.0.8.8/download/真机调试.tar.gz
    //http://10.0.8.8/download/真机调试.tar.gz
    
    NSString *urlString = @"http://10.0.8.8/download/真机调试.tar.gz";
    NSData *data = [[NSData alloc]initWithContentsOfURL:[NSURL URLWithString:urlString]];
    NSLog(@"size = %u",data.length);

}
为什么使用多线程,解决什么样的问题

  2.3使用通知监听线程的结束

技术分享
3)使用通知监听线程的结束
    [[NSNotificationCenter defaultCenter]addObserver:self selector:@selector(dealThreadExit) name:NSThreadWillExitNotification object:nil];
#pragma mark -- (3)使用通知监听线程的结束
-(void)dealThreadExit{
    NSLog(@"线程结束");
}
使用通知监听线程的结束

  2.4线程的同步和锁

技术分享
    (5)线程的同步和锁
    演示问题:多个线程访问同一块内存
    为什么出问题
        CPU和内存(_num)

    //项目开发:nonatomic当一个属性只有UI界面访问可以加上,提高速度
    //  当这个属性页会被创建的子线程访问时不要加nonatomic保证线程的安全
    //
    //如何解决问题
    _lock = [[NSLock alloc]init];

    [NSThread detachNewThreadSelector:@selector(add) toTarget:self withObject:nil];
    [NSThread detachNewThreadSelector:@selector(sub) toTarget:self withObject:nil];

#pragma mark -- (5)线程的同步和锁
-(void)add{
    for (int i = 0; i <100; i++) {
        [_lock lock];
        _num ++;
        [_lock unlock];
        NSLog(@"add = %d",_num);
    }
}

-(void)sub{
    for (int i = 0; i <100; i++) {
        [_lock lock];
        _num --;
        [_lock unlock];
        NSLog(@"sub = %d",_num );
    }
    
}
线程的同步和锁

  2.5子线程如何更新UI

技术分享
    (6)子线程如何更新UI(非常重要,不会代码会出现问题)
    //限制: UI线程称为主线程
    //      其他创建的线程称为工作子线程
    //      注意: 不要再子线程中直接操作UI(间接让主线程操作UI)
    //下载进度更新
    _progressView = [[UIProgressView alloc]initWithFrame:CGRectMake(10, 200, 300, 20)];
    [self.view addSubview:_progressView];
    [NSThread detachNewThreadSelector:@selector(downloadNetworkdata) toTarget:self withObject:nil];

#pragma mark -- (6)子线程如何更新UI(非常重要,不会代码会出现问题)
-(void)downloadNetworkdata{
    for (int i = 0;  i< 100; i++) {
        //_progressView.progress +=.01;
        [self performSelectorOnMainThread:@selector(updataUI) withObject:nil waitUntilDone:YES];
        [NSThread sleepForTimeInterval:.1];
    }
}

-(void)updataUI{
    _progressView.progress +=.1;
    if (_progressView.progress == 1) {
        NSLog(@"=========");
        [_progressView removeFromSuperview];
    }
}
子线程如何更新UI

 

3.NSOperation

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    
    //NSOperation 的使用 (操作、行动)
    //(1)什么是NSOperation,作用
    //      NSOperation和NSThread相似,实现多线程的一种机制
    //      在NSThread做了更高的抽象,加入了block,比NSThread更简单易用
    
    //NSOperation抽象类,使用NSInvocationOperation和NSBlockOperation
    
    //(2)NSInvocationOperation
    NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(task1) object:nil];
    //注意: 创建后需要执行,执行的时候默认是同步的
//    [invocationOperation start];
    
    //(3)NSBlockOperation
    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        for (int i = 0; i <20 ; i++) {
            NSLog(@"B = %d",i);
        }

    }];
//    [blockOperation start];
    
    //(4)NSOperationQueue操作队列,理解为:任务列表
    //注意:任务会异步平行执行
    NSOperationQueue *queue = [[NSOperationQueue alloc]init];
    [queue addOperations:@[invocationOperation,blockOperation] waitUntilFinished:NO];
    [queue addOperation:invocationOperation];
    [queue addOperation:blockOperation];
    
}


-(void)task1{
    for (int i = 0; i <20 ; i++) {
        NSLog(@"A = %d",i);
    }
}

 

4.GCD

  4.1GCD的使用 (Grand Central Dispatch 简写)

    好处:  1.支持多核心

           2.C和block接口, 易于使用

           3.较晚出现, 功能强大, 推荐使用

  4.2创建一个异步任务

-(void)createAsyncTask
{
    // 创建一个异步任务
    //参数1: 传入queue, 有三种queue
    //   main queue 主队列(UI主线程)
    //   global queue 全局队列(理解为工作线程)
    //   自定义的queue
    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(queue, ^{
        for (int i=0; i<20; i++) {
            NSLog(@"A = %d",i);
        }
    });
    dispatch_async(queue, ^{
        for (int i=0; i<20; i++) {
            NSLog(@"B = %d",i);
        }
    });
    
}

 

  4.3模拟网络下载

-(void)simulateNetworkDownload
{
    progressView = [[UIProgressView alloc] initWithFrame:CGRectMake(10, 100, 300, 20)];
    [self.view addSubview:progressView];
    
    //GCD最简单开启异步任务的形式
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
       
        for(int i=0; i<100; i++)
        {
            //子线程中不能直接更新UI
            //progressView.progress += 0.01;
            dispatch_async(dispatch_get_main_queue(), ^{
                progressView.progress += 0.01;
            });
            
            NSLog(@"progress = %.2f%%",progressView.progress*100);
            
            [NSThread sleepForTimeInterval:0.1];
        }
        
        //最后显示对话框
        dispatch_async(dispatch_get_main_queue(), ^{
            UIAlertView *alertView = [[UIAlertView alloc] init];
            alertView.message = @"下载完成";
            [alertView addButtonWithTitle:@"取消"];
            [alertView show];
        });
        
    });
  
}

 

  4.4只执行一次, 实现单例(推荐实现的方式,线程安全)

-(void)runOnce
{
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSLog(@"只执行一次的代码");
    });
}

 

  4.5延时执行

-(void)delayRun
{
    //5s 后输出hehe
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        NSLog(@"he he");
    });
    
    
}

 

  4.6同时执行多个任务, 等待所有任务执行完成进行处理(类似迅雷

    实例:   迅雷所有任务完成之后自动关机

-(void)groupRun
{
    // group 任务组
    dispatch_group_t group = dispatch_group_create();
    
    //添加任务  7s完成
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        for (int i=0; i<100; i++) {
            NSLog(@"A = %d",i);
            [NSThread sleepForTimeInterval:0.07];
        }
    });
    
    // 5s完成
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        for (int i=0; i<100; i++) {
            NSLog(@"B = %d",i);
            [NSThread sleepForTimeInterval:0.05];
        }
    });
    
    // 10s完成
    dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        for (int i=0; i<100; i++) {
            NSLog(@"C = %d",i);
            [NSThread sleepForTimeInterval:0.1];
        }
    });
    
    dispatch_group_notify(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSLog(@"所有任务执行完成, 自动关机");
    });
    
}

 

 

郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。