多线程

本文详细介绍了iOS开发中多线程的基本概念和技术实现方法,包括使用NSObject提供的多线程方法、NSThread类、NSOperation队列及GCD等技术手段进行多线程编程的具体实践。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

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

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




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值