关于线程的概念不在赘述,网上讲的很详细,IOS中主要提供了3种方式实现多线程,分别是NSThread,NSOperation以及GCD,这里我们总结下最基础的NSThread

1 线程创建

可以使用NSthread提供的方法创建一个新的线程,创建方法有如下两种

a.+ (void)detachNewThreadSelector:(SEL)selector toTarget:(id)target withObject:(id)argument;

b.- (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument

前一种方式创建了一个新的线程并立马执行线程任务,后一种方式创建了一个新的线程,方法返回NSThread的实例,当调用- (void)start时才会执行线程任务

多线程常用的使用场景是当一些耗时的操作(比如下载)运行在主线程时,主线程会被阻塞住,给用户一种"卡住"的感觉,所以我们需要把这些耗时的操作放到子线程中,主线程只处理UI操作以及一些时间代价下的操作。

- (void)viewDidLoad
{[super viewDidLoad];[NSThread detachNewThreadSelector:@selector(doInMutableThread) toTarget:self withObject:nil];
}- (void)doInMutableThread {[NSThread sleepForTimeInterval:3];NSLog(@"%@",[NSThread currentThread]);
}

上面代码中sleepForTimeInterval使执行此函数的线程睡眠3秒用来模拟耗时操作,3秒后再继续执行后面的代码

下面再来看一个完整的例子,当点击下载按钮后,开启8个子线程下载图片,下载完成后通过方法performSelectorOnMainThread回到主线程更新UI(IOS中UI相关的操作必须执行在主线程中)

#import "ZLTViewController.h"@interface ZLTViewController () {UIImageView *_imageView1;UIImageView *_imageView2;UIImageView *_imageView3;UIImageView *_imageView4;UIImageView *_imageView5;UIImageView *_imageView6;UIImageView *_imageView7;UIImageView *_imageView8;UIButton *_loadButton;NSArray *_imageUrlArray;
}@end@implementation ZLTViewController- (void)viewDidLoad
{[super viewDidLoad];// Do any additional setup after loading the view, typically from a nib.
    [self setUpView];
}- (void)setUpView {_imageView1 = [[UIImageView alloc] initWithFrame:CGRectMake(20, 20, 120, 100)];_imageView2 = [[UIImageView alloc] initWithFrame:CGRectMake(20, 130, 120, 100)];_imageView3 = [[UIImageView alloc] initWithFrame:CGRectMake(20, 240, 120, 100)];_imageView4 = [[UIImageView alloc] initWithFrame:CGRectMake(20, 350, 120, 100)];_imageView5 = [[UIImageView alloc] initWithFrame:CGRectMake(170, 20, 120, 100)];_imageView6 = [[UIImageView alloc] initWithFrame:CGRectMake(170, 130, 120, 100)];_imageView7 = [[UIImageView alloc] initWithFrame:CGRectMake(170, 240, 120, 100)];_imageView8 = [[UIImageView alloc] initWithFrame:CGRectMake(170, 350, 120, 100)];_imageUrlArray = @[@"http://www.iyi8.com/uploadfile/2014/1002/20141002112239407.jpg",@"http://www.iyi8.com/uploadfile/2014/1002/20141002112240514.jpg",@"http://www.iyi8.com/uploadfile/2014/1002/20141002112248343.jpg",@"http://www.iyi8.com/uploadfile/2014/1002/20141002112236540.jpg",@"http://www.iyi8.com/uploadfile/2014/1002/20141002112242679.jpg",@"http://www.iyi8.com/uploadfile/2014/1002/20141002112243630.jpg",@"http://www.iyi8.com/uploadfile/2014/1002/20141002112245663.jpg",@"http://www.iyi8.com/uploadfile/2014/1002/20141002112247219.jpg"];_loadButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];_loadButton.frame = CGRectMake(120, 490, 80, 30);[_loadButton setTitle:@"下载" forState:UIControlStateNormal];[_loadButton addTarget:self action:@selector(downImage) forControlEvents:UIControlEventTouchUpInside];[self.view addSubview:_imageView1];[self.view addSubview:_imageView2];[self.view addSubview:_imageView3];[self.view addSubview:_imageView4];[self.view addSubview:_imageView5];[self.view addSubview:_imageView6];[self.view addSubview:_imageView7];[self.view addSubview:_imageView8];[self.view addSubview:_loadButton];
}- (void)downImage {for (int i = 0; i < _imageUrlArray.count; i++) {//[NSThread detachNewThreadSelector:@selector(loadImage:) toTarget:self withObject:[NSNumber numberWithInt:i]];
        NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(loadImage:) object:[NSNumber numberWithInt:i]];thread.name = [NSString stringWithFormat:@"thread%d",i];[thread start];}
}- (void)loadImage:(NSNumber *)index {@autoreleasepool {NSLog(@"%@",[NSThread currentThread]);int i = [index intValue];NSString *urlStr = _imageUrlArray[i];NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlStr]];UIImage *image = [UIImage imageWithData:data];NSDictionary *dic = @{@"index":index,@"image":image};[self performSelectorOnMainThread:@selector(updateImageView:) withObject:dic waitUntilDone:YES];}
}- (void)updateImageView:(NSDictionary *)dic {switch ([dic[@"index"] intValue]) {case 0:_imageView1.image = dic[@"image"];break;case 1:_imageView2.image = dic[@"image"];break;case 2:_imageView3.image = dic[@"image"];break;case 3:_imageView4.image = dic[@"image"];break;case 4:_imageView5.image = dic[@"image"];break;case 5:_imageView6.image = dic[@"image"];break;case 6:_imageView7.image = dic[@"image"];break;case 7:_imageView8.image = dic[@"image"];break;}
}@end

上面的例子中我把子线程方法放在了自动释放池中,那是因为在消息循环中系统会自动为主线程创建自动释放池,但不会为子线程创建自动释放池,所以需要我们手动创建

2 线程状态

线程有3种状态:执行中(isExecuting),执行结束(isFinished),取消执行(isCancelled)

我们可以向线程发送消息cancel取消线程,但是cancel仅仅使线程isCancelled返回YES而已,我们需要在代码中判断线程的状态,并调用exit终结当前线程。

给上面程序加上停止按钮,通过设置线程状态停止图片加载。

//
//  ZLTViewController.m
//  IOS多线程
//
//  Created by user on 14-10-28.
//  Copyright (c) 2014年 臧立涛. All rights reserved.
//

#import "ZLTViewController.h"@interface ZLTViewController () {UIImageView *_imageView1;UIImageView *_imageView2;UIImageView *_imageView3;UIImageView *_imageView4;UIImageView *_imageView5;UIImageView *_imageView6;UIImageView *_imageView7;UIImageView *_imageView8;UIButton *_loadButton;NSArray *_imageUrlArray;//线程数组NSMutableArray *_threadArray;UIButton *_stopButton;
}@end@implementation ZLTViewController- (void)viewDidLoad
{[super viewDidLoad];// Do any additional setup after loading the view, typically from a nib.
    [self setUpView];
}- (void)setUpView {_imageView1 = [[UIImageView alloc] initWithFrame:CGRectMake(20, 20, 120, 100)];_imageView2 = [[UIImageView alloc] initWithFrame:CGRectMake(20, 130, 120, 100)];_imageView3 = [[UIImageView alloc] initWithFrame:CGRectMake(20, 240, 120, 100)];_imageView4 = [[UIImageView alloc] initWithFrame:CGRectMake(20, 350, 120, 100)];_imageView5 = [[UIImageView alloc] initWithFrame:CGRectMake(170, 20, 120, 100)];_imageView6 = [[UIImageView alloc] initWithFrame:CGRectMake(170, 130, 120, 100)];_imageView7 = [[UIImageView alloc] initWithFrame:CGRectMake(170, 240, 120, 100)];_imageView8 = [[UIImageView alloc] initWithFrame:CGRectMake(170, 350, 120, 100)];_imageUrlArray = @[@"http://www.iyi8.com/uploadfile/2014/1002/20141002112239407.jpg",@"http://www.iyi8.com/uploadfile/2014/1002/20141002112240514.jpg",@"http://www.iyi8.com/uploadfile/2014/1002/20141002112248343.jpg",@"http://www.iyi8.com/uploadfile/2014/1002/20141002112236540.jpg",@"http://www.iyi8.com/uploadfile/2014/1002/20141002112242679.jpg",@"http://www.iyi8.com/uploadfile/2014/1002/20141002112243630.jpg",@"http://www.iyi8.com/uploadfile/2014/1002/20141002112245663.jpg",@"http://www.iyi8.com/uploadfile/2014/1002/20141002112247219.jpg"];_threadArray = [NSMutableArray array];_loadButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];_loadButton.frame = CGRectMake(80, 490, 80, 30);[_loadButton setTitle:@"下载" forState:UIControlStateNormal];[_loadButton addTarget:self action:@selector(downImage) forControlEvents:UIControlEventTouchUpInside];_stopButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];_stopButton.frame = CGRectMake(160, 490, 80, 30);[_stopButton setTitle:@"停止" forState:UIControlStateNormal];[_stopButton addTarget:self action:@selector(stopDownImage) forControlEvents:UIControlEventTouchUpInside];[self.view addSubview:_imageView1];[self.view addSubview:_imageView2];[self.view addSubview:_imageView3];[self.view addSubview:_imageView4];[self.view addSubview:_imageView5];[self.view addSubview:_imageView6];[self.view addSubview:_imageView7];[self.view addSubview:_imageView8];[self.view addSubview:_loadButton];[self.view addSubview:_stopButton];
}- (void)stopDownImage {for (int i = 0; i < _threadArray.count; i++) {//如果线程未结束则停止if (![_threadArray[i] isFinished]) {[_threadArray[i] cancel];}}
}
- (void)downImage {for (int i = 0; i < _imageUrlArray.count; i++) {//[NSThread detachNewThreadSelector:@selector(loadImage:) toTarget:self withObject:[NSNumber numberWithInt:i]];
        NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(loadImage:) object:[NSNumber numberWithInt:i]];thread.name = [NSString stringWithFormat:@"thread%d",i];[_threadArray addObject:thread];[thread start];}
}- (void)loadImage:(NSNumber *)index {@autoreleasepool {int i = [index intValue];NSString *urlStr = _imageUrlArray[i];NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlStr]];NSThread *thread = [NSThread currentThread];if ([thread isCancelled]) {//取消当前线程
            [NSThread exit];}UIImage *image = [UIImage imageWithData:data];NSDictionary *dic = @{@"index":index,@"image":image};[self performSelectorOnMainThread:@selector(updateImageView:) withObject:dic waitUntilDone:YES];}
}- (void)updateImageView:(NSDictionary *)dic {switch ([dic[@"index"] intValue]) {case 0:_imageView1.image = dic[@"image"];break;case 1:_imageView2.image = dic[@"image"];break;case 2:_imageView3.image = dic[@"image"];break;case 3:_imageView4.image = dic[@"image"];break;case 4:_imageView5.image = dic[@"image"];break;case 5:_imageView6.image = dic[@"image"];break;case 6:_imageView7.image = dic[@"image"];break;case 7:_imageView8.image = dic[@"image"];break;}
}@end

3 线程优先级

我们可以通过threadPriority获取或者设置线程的优先级,这个属性的取值范围是0至1,数字越大表示优先级越高,越有可能获得调度,创建线程默认的优先级为0.5

NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(loadImage) object:nil];thread.name = @"thread";//获取线程优先级
        [thread threadPriority];//设置线程优先级thread.threadPriority = 0.5;

4 分类扩展

NSObject提供了方法用来更方便的实现多线程,这些方法使用的就是NSThread

@interface NSObject (NSThreadPerformAdditions)

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array;

- (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait;

- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait modes:(NSArray *)array

- (void)performSelector:(SEL)aSelector onThread:(NSThread *)thr withObject:(id)arg waitUntilDone:(BOOL)wait

- (void)performSelectorInBackground:(SEL)aSelector withObject:(id)arg

@end

转载于:https://www.cnblogs.com/zanglitao/p/4060643.html

IOS多线程之NSThread相关推荐

  1. ios多线程之NSThread头文件详解

    1.NSThread 头文件中的相关方法 //获取当前线程+(NSThread *)currentThread; //创建线程后自动启动线程 + (void)detachNewThreadSelect ...

  2. iOS多线程之GCD小记

    iOS多线程之GCD小记 iOS多线程方案简介 从各种资料中了解到,iOS中目前有4套多线程的方案,分别是下列4中: 1.Pthreads 这是一套可以在很多操作系统上通用的多线程API,是基于C语言 ...

  3. 多线程之NSThread

    关于多线程会有一系列如下: 多线程之概念解析 多线程之pthread, NSThread, NSOperation, GCD 多线程之NSThread 多线程之NSOperation 多线程之GCD ...

  4. iOS多线程编程之NSThread的使用(★★★推荐,为原作者点赞★★★)

    文章来源:http://blog.csdn.net/totogo2010/article/details/8010231 1.简介: 1.1 iOS有三种多线程编程的技术,分别是: 1..NSThre ...

  5. (五十五)iOS多线程之GCD

    GCD的全称为Grand Central Dispatch,翻译为大中央调度,是Apple开发的一个多线程编程解决方法. 进程和线程的概念: 正在进行中的程序被称为进程,负责程序运行的内存分配,每一个 ...

  6. IOS多线程之Block编程

    1 什么是block iOS SDK 4.0開始,Apple引入了block这一特性.字面上说,block就是一个代码块.可是它的奇妙之处在于在内联(inline)运行的时候(这和C++非常像)还能够 ...

  7. iOS多线程之7.NSOperation的初识

    NSOperation和GCD一样,不用我们管理线程的生命周期,加锁等问题,只要把操作封装进NSOperation中,系统会自动帮我们创建线程,执行操作.而且他是面向对象的,我们看起来更容易理解,使用 ...

  8. (五十六)iOS多线程之NSOperation

    NSOpertation是一套OC的API,是对GCD进行的Cocoa抽象. NSOperation有两种不同类型的队列,主队列和自定义队列. 主队列运行于主线程上,自定义队列在后台运行. [NSBl ...

  9. linux 线程pthread_detach,linux线程之pthread_join和pthread_detach

    在任何一个时间点上,线程是可结合的(joinable)或者是分离的(detached).一个可结合的线程能够被其他线程收回其资源和杀死.在 被其他线程回收之前,它的存储器资源(例如栈)是不释放的.相反 ...

  10. iOS网络编程之Socket

    [深入浅出Cocoa]iOS网络编程之Socket 罗朝辉 (http://blog.csdn.net/kesalin) CC 许可,转载请注明出处 更多 Cocoa 开发文章,敬请访问<深入浅 ...

最新文章

  1. 【旧文章搬运】Win7可变对象头结构之InfoMask解析
  2. python找出在原图中的位置_用python简单处理图片(4):图像中的像素访问
  3. 硬件——STM32 , 录音
  4. 避免Eclipse经常出现Out Of Memory
  5. linux内核那些事之buddy
  6. leetcode - 983. 最低票价
  7. 简述UTF-8编码原理及其文本文件的读写技术 【转】
  8. VMProtect Ultimate 加壳脱壳工
  9. 【侯捷】C++内存管理机制
  10. (一)从零开始学习模糊控制——基本概念
  11. python爬虫基础爬取用户头像实战
  12. PymuPDF实现PDF文字和图片的修改
  13. 高电平和低电平 到底是啥?
  14. 如何在VSCode设置/取消隐藏文件
  15. 解析LDO的五大作用,这里有你意想不到的答案
  16. Java脚本写的随机验证码
  17. Lodop打印设计(PRINT_DESIGN)介绍
  18. 直饮加热一体机哪个牌子好,净水器科普
  19. codeforces1430E String Reversal
  20. Django入门教程(八)Form表单

热门文章

  1. php如何接受用户邮箱发送信息,怎么将用户购物车的产品发送到邮箱
  2. qt控制程序打开记事本_Qt 记事本程序
  3. Python降低XGBoost 过度拟合多种方法
  4. VTK(三)---在Linux系统上配置NDI Aurora磁导航API(用于手术导航系统的开发)
  5. video-react报错pause没有被定义_qt常见报错
  6. hbase 查询某列_hbase shell使用STARTROW、ENDROW、FILTER查出指定的列
  7. iOS 指令集架构Architectures armv6、armv7、armv7s、arm64、arm64e、x86_64、i386
  8. 【证明】两个自变量的二阶线性方程经过可逆变换后方程的类型不会改变
  9. aes加密c语言实现,基于C语言实现的aes256加密算法示例
  10. 巨人 index.php/user/login,dedecms实现首页顶部会员登陆框的方法