多线程

    xiaoxiao2021-03-26  27

    一个运行的程序就是一个进程或者叫做一个任务

    一个进程至少包含一个线程,线程是程序的执行流

    iOS 程序启动时,在创建一个进程的同事,会开始运行一个程序,该程序被称作主线程

    主线程是其他线程最终的父线程,所有界面的显示操作必须在主线程进行!!!!

    后台线程无法更新UI界面和响应用户点击事件

    系统中的每一个进程都是有自己独立的虚拟内存空间,而同一个进程中的多个线程则公用进程的内存空间

    每创建一个新的线程,都会消耗一定内存的CPU时间

    当多线程对同一个资源出现争夺的时候需要注意线程安全问题

    线程的使用不是无节制的 :iOS 主线程的堆栈大小是1M,从第二个线程开始就是512KB,这些数值不能通过编译器开关和线程API函数更改 

    只有主线程有直接修改UI的能力

     

    一、NSObject多线程方法

    1、[NSThread currentThread]; 可以返回当前运行的线程

          num = 1 说明是主线程

          在任务多线程技术中,均可以使用此方法查看当前的线程情况。

    2、新建后台线程,调度任务

         [self performSelectorInBackground:@selector(bgTask) withObject:nil];

         使用performSelectorInBackground是可以修改UI的,不是强烈不建议这样使用。

    3、更新界面

         使用performSelectorOnMainThread可以在主线程上执行任务。

         提示:NSObject对象均可以调用此方法。

    4、内存管理

         线程任务要包在@autoreleasepool(自动释放池)中,否则容易引起内存泄露,而且非常难发现。

    5、总结:使用简单,量级轻,不能控制线程的执行顺序

    例如:

    @implementation ViewController

    - (void)viewDidLoad {

        [super viewDidLoad];

        UIButton *button1 =[UIButton buttonWithType:UIButtonTypeCustom];

        button1.backgroundColor =[UIColor redColor];

        button1.frame =CGRectMake(50, 50, 100, 50);

        [button1 setTitle:@"耗时操作" forState:UIControlStateNormal];

        [button1 addTarget:self action:@selector(buttton1) forControlEvents:UIControlEventTouchUpInside];

        [self.view addSubview:button1];

        UIButton *button2 =[UIButton buttonWithType:UIButtonTypeCustom];

        button2.backgroundColor =[UIColor redColor];

        button2.frame =CGRectMake(50, 150, 100, 50);

        [button2 setTitle:@"普通操作" forState:UIControlStateNormal];

        [button2 addTarget:self action:@selector(button2) forControlEvents:UIControlEventTouchUpInside];

        [self.view addSubview:button2];

    }

    -(void)buttton1

    {

        //后台耗时操作

        //performSelectorInBackground会创建一个后台线程,并在该线程中执行调用的方法

    //    performSelectorInBackground是可以修改UI的但是强烈不建议使用

        [self performSelectorInBackground:@selector(bgTask) withObject:nil];

    }

    -(void)button2

    {

    }

    -(void)bgTask

    {

        @autoreleasepool {

            for (int i = 0; i  < 30000000; i++) {

                NSLog(@"%d",i);

            }

            //在主线程中修改所需要的操作或界面内容;withObject:所需要传递的参数

            [self performSelectorOnMainThread:@selector(change) withObject:nil waitUntilDone:YES];

        }

    }

    -(void)change

    {

    }

    二、NThread

     1、类方法

    detachNewThreadSelector直接启动线程,调用选择器方法

    2、成员方法

    initWithTarget需要使用start方法才能启动实例化出来的线程

    优点:简单

    缺点:控制线程的生命周期比较困难

               控制并发线程数

               先后顺序困难

    例如:

    #import "ViewController.h"

    @interface ViewController ()

    @property(nonatomic,strong)NSSet *imageViewSet;

    @end

    @implementation ViewController

    -(void)setUpUI{

        //实例化图像视图集合

        NSMutableSet *imageSet = [NSMutableSet setWithCapacity:28];

        NSInteger w = self.view.frame.size.width/8;

        NSInteger h = self.view.frame.size.height/8;

        for (int row = 0; row < 7; row++) {

            for (int col = 0; col < 4; col++) {

                //计算图片的位置

                NSInteger x = col * w;

                NSInteger y = row * h;

                UIImageView *imageview =[[UIImageView alloc]initWithFrame:CGRectMake(x, y, w, h)];

                //顺序填充图片

                NSInteger num = (row * 4 * col) % 17 + 1;

                NSString *imageName =[NSString stringWithFormat:@"图片名称%ld",num];

                UIImage *image = [UIImage imageNamed:imageName];

                [imageview setImage:image];

                [self.view addSubview:imageview];

                [imageSet addObject:imageview];

                

            }

        }

        self.imageViewSet = imageSet;

        //添加按钮

        UIButton *button =[UIButton buttonWithType:UIButtonTypeRoundedRect];

        [button setFrame:CGRectMake(110, self.view.frame.size.height - 80, 100, 50)];

        [button setTitle:@"刷新图片" forState:UIControlStateNormal];

        [button addTarget:self action:@selector(click) forControlEvents:UIControlEventTouchUpInside];

        [self.view addSubview:button];

        

    }

    -(void)click

    {

        [self threadLoad];

    }

    #pragma mark - NSThread方法

    -(void)threadLoadImage:(UIImageView *)imageView{

        @autoreleasepool {

            NSInteger num = arc4random_uniform(17) + 1;

            NSString *imageName = [NSString stringWithFormat:@"图片名称%ld",num];

            UIImage *image =[UIImage imageNamed:imageName];

            //主线程更新UI

            [imageView performSelectorOnMainThread:@selector(setImage:) withObject:image waitUntilDone:YES];

          

        }

       

    }

    -(void)threadLoad

    {

        for (UIImageView *imagev in self.imageViewSet) {

            //新建线程调用threadLoadImage方法

    //        [NSThread detachNewThreadSelector:@selector(threadLoadImage:) toTarget:self withObject:imagev];

            NSThread *thread = [[NSThread alloc]initWithTarget:self selector:@selector(threadLoadImage:) object:imagev];

            //启动线程

            [thread start];

        }

    }

    - (void)viewDidLoad {

        [super viewDidLoad];

        

        [self setUpUI];

        

    }

    三、NSOperation

    1、 NSOperation的两个子类NSInvocationOperation, NSBlockOperation

    例如:

    #import "ViewController.h"

    @interface ViewController ()

    @property(nonatomic,strong)NSSet *imageViewSet;

    @property(strong,nonatomic)NSOperationQueue *queue;

    @end

    @implementation ViewController

    -(void)setUpUI{

        //实例化图像视图集合

        NSMutableSet *imageSet = [NSMutableSet setWithCapacity:28];

        NSInteger w = self.view.frame.size.width/8;

        NSInteger h = self.view.frame.size.height/8;

        for (int row = 0; row < 7; row++) {

            for (int col = 0; col < 4; col++) {

                //计算图片的位置

                NSInteger x = col * w;

                NSInteger y = row * h;

                UIImageView *imageview =[[UIImageView alloc]initWithFrame:CGRectMake(x, y, w, h)];

                //顺序填充图片

                NSInteger num = (row * 4 * col) % 17 + 1;

                NSString *imageName =[NSString stringWithFormat:@"图片名称%ld",num];

                UIImage *image = [UIImage imageNamed:imageName];

                [imageview setImage:image];

                [self.view addSubview:imageview];

                [imageSet addObject:imageview];

                

            }

        }

        self.imageViewSet = imageSet;

        //添加按钮

        UIButton *button =[UIButton buttonWithType:UIButtonTypeRoundedRect];

        [button setFrame:CGRectMake(110, self.view.frame.size.height - 80, 100, 50)];

        [button setTitle:@"刷新图片" forState:UIControlStateNormal];

        [button addTarget:self action:@selector(click) forControlEvents:UIControlEventTouchUpInside];

        [self.view addSubview:button];

        

        

    }

    -(void)click

    {

       // [self operationLoad];

        [self operationBlockLoad];

    }

    #pragma mark - NSOperation方法

    -(void)operationBlockLoad

    {

        for (UIImageView *imagev in self.imageViewSet) {

        NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{

            [self operationLoadImage:imagev];

        }];

            [self.queue addOperation:op];

        }

    }

    -(void)operationLoadImage:(UIImageView *)imageView{

        @autoreleasepool {

            NSInteger num = arc4random_uniform(17) + 1;

            NSString *imageName = [NSString stringWithFormat:@"图片名称%ld",num];

            UIImage *image =[UIImage imageNamed:imageName];

            //主线程更新UI

          [[NSOperationQueue mainQueue]addOperationWithBlock:^{

              [imageView setImage:image];

          }];

          

        }

       

    }

    -(void)operationLoad

    {

        //队列可以设置同时并发线程的数量

        [self.queue setMaxConcurrentOperationCount:3];

        for (UIImageView *imagev in self.imageViewSet) {

            NSInvocationOperation *op =[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(operationLoadImage:) object:imagev];

            //如果直接调用start,实在主线程队列上运行的,不会开启新的线程

            [op start];

            //Invocation添加到队列,一添加到队列,就会开启新的线程执行任务

            [self.queue addOperation:op];

        }

    }

    #pragma mark - NSOperation操作之间的顺序

    -(void)operationDemo

    {

        NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{

            

        }];

        NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{

            

        }];

        NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{

            

        }];

        //Dependency依赖 依赖关系可以多重依赖

        [op2 addDependency:op1];

        [op3 addDependency:op2];

        [self.queue addOperation:op3];

        [self.queue addOperation:op1];

        [self.queue addOperation:op2];

    }

    - (void)viewDidLoad {

        [super viewDidLoad];

        

        [self setUpUI];

        //实例化操作队列

        self.queue = [[NSOperationQueue alloc]init];

        

    }

    四、GCD

    #import "ViewController.h"

    @interface ViewController ()

    @property(nonatomic,strong)NSSet *imageViewSet;

    @end

    @implementation ViewController

    -(void)setUpUI{

        //实例化图像视图集合

        NSMutableSet *imageSet = [NSMutableSet setWithCapacity:28];

        NSInteger w = self.view.frame.size.width/8;

        NSInteger h = self.view.frame.size.height/8;

        for (int row = 0; row < 7; row++) {

            for (int col = 0; col < 4; col++) {

                //计算图片的位置

                NSInteger x = col * w;

                NSInteger y = row * h;

                UIImageView *imageview =[[UIImageView alloc]initWithFrame:CGRectMake(x, y, w, h)];

                //顺序填充图片

                NSInteger num = (row * 4 * col) % 17 + 1;

                NSString *imageName =[NSString stringWithFormat:@"图片名称%ld",num];

                UIImage *image = [UIImage imageNamed:imageName];

                [imageview setImage:image];

                [self.view addSubview:imageview];

                [imageSet addObject:imageview];

                

            }

        }

        self.imageViewSet = imageSet;

        //添加按钮

        UIButton *button =[UIButton buttonWithType:UIButtonTypeRoundedRect];

        [button setFrame:CGRectMake(110, self.view.frame.size.height - 80, 100, 50)];

        [button setTitle:@"刷新图片" forState:UIControlStateNormal];

        [button addTarget:self action:@selector(click) forControlEvents:UIControlEventTouchUpInside];

        [self.view addSubview:button];

        

        

    }

    -(void)click

    {

        [self gcdLoad];

        

    }

    #pragma mark - GCD加载图像

    -(void)gcdLoad

    {

        //派发dispatch 异步async执行,并发执行

        //PRIORITY优先级,一般选择默认的即可

        //获取全局队列

        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

               for (UIImageView *imagev in self.imageViewSet) {

                   dispatch_async(queue, ^{

                       NSInteger num = arc4random_uniform(17) + 1;

                       NSString *imageName = [NSString stringWithFormat:@"图片名称%ld",num];

                       UIImage *image =[UIImage imageNamed:imageName];

                       //设置图像,在主线程队列设置UI

                       dispatch_async(dispatch_get_main_queue(), ^{

                           [imagev setImage:image];

                       });

                   });

            }

      

    }

    #pragma mark - GCD

    -(void)gcdDemo

    {

        //全局队列中调用异步任务 开发时候不用考虑并发线程数量问题

    //    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

    //    dispatch_async(queue, ^{

    //        

    //    });

        //    dispatch_async(queue, ^{

        //

        //    });

        //    dispatch_async(queue, ^{

        //

        //    });

        //串行队列,需要创建,不能够get

        dispatch_queue_t queue = dispatch_queue_create("myQUeue", DISPATCH_QUEUE_SERIAL);

           dispatch_async(queue, ^{

        

            });

           dispatch_async(queue, ^{

            

           });

           dispatch_async(queue, ^{

            

           });

        

    }

    - (void)viewDidLoad {

        [super viewDidLoad];

        

        [self setUpUI];

        

    }

    @end

    转载请注明原文地址: https://ju.6miu.com/read-663591.html

    最新回复(0)