UI进阶 多线程
一、多线程概述
- 程序、进程、线程
- 程序:由源代码生成的可执行应用。(例如:QQ.app)
- 进程:一个正在运行的程序可以看做一个进程。(例如:正在运行的QQ就是一个进程),进程拥有独立运行所需的全部资源。
- 线程:程序中独立运行的代码段。(例如:接收QQ消息的代码)
一个进程是由一或多个线程组成。进程只负责资源的调度和分配,线程才是程序真正的执行单元,负责代码的执行。
- 单线程
- 每个正在运行的程序(即进程),至少包含一个线程,这个线程叫主线程。
- 主线程在程序启动时被创建,用于执行main函数。
- 只有一个主线程的程序,称作单线程程序。
- 在单线程程序中,主线程负责执行程序的所有代码(UI展现以及刷新,网络请求,本地存储等等)。这些代码只能顺序执行,无法并发执行。
- 多线程
- 拥有多个线程的程序,称作多线程程序。
- iOS允许用户自己开辟新的线程,相对于主线程来讲,这些线程,称作子线程。
- 可以根据需要开辟若干子线程
- 子线程和主线程 都是 独立的运行单元,各自的执行互不影响,因此能够并发执行。
- 单线程、多线程区别
- 单线程程序:只有一个线程,即主线程,代码顺序执行,容易出现代码阻塞(页面假死)。
- 多线程程序:有多个线程,线程间独立运行,能有效的避免代码阻塞,并且提高程序的运行性能。
- 注意:iOS中关于UI的添加和刷新必须在主线程中操作。
二、iOS平台下的多线程
- iOS多线程实现种类
- NSThread
- NSOperationQueue
- NSObject
- GCD
三、NSThread
- NSThread是一个轻量级的多线程,它有以下两种创建方法
方法 功能 - (id)initWithTarget:(id)target selector:(SEL)selector object:(id)argument 初始化一个子线程,但需要手动开启 + (void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject:(id)anArgument 初始化一个子线程并自动开启 -start 开启子线程 -cancel 取消当前子线程,不是真正的取消,而是给子线程发送了一个“取消”消息,标记为canceled +exit 直接将线程退出
- 第一种:手动开辟一个子线程
- (void)viewDidLoad {
#pragma mark - NSThread手动开辟子线程
// 参数1: target
// 参数2: 方法
// 参数3: 要传的参数
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(sayHello:) object:@"说你好!"];
#pragma mark - 启动子线程
[thread start]; // 判断一个线程是否正在执行
NSLog(@"是否正在执行%d",[thread isExecuting]);
// 判断一个线程是否完成了任务(是否执行完毕)
NSLog(@"是否执行完毕%d", [thread isFinished]); #pragma mark - 释放子线程的两种方式
// 第一种:取消线程,不是真正的取消,而是给子线程发送了一个“取消”消息,标记为canceled
// 判断线城是否被标记为canceled
// NSLog(@"%d", [thread isCancelled]);
// [thread cancel];
// // 第二种:直接将线程退出
// [NSThread exit]; } - (void)sayHello:(NSString *)hello {
NSLog(@"%@", hello);
// 打印当前线程
NSLog(@"当前线程:%@", [NSThread currentThread]);
NSLog(@"主线程:%@", [NSThread mainThread]);
}Thread手动开辟一个子线程
开辟子线程成功
- 第一种:手动开辟一个子线程
第二种:
- (void)viewDidLoad {
#pragma mark - NSThread自动开辟子线程
// 线程自动开启,不需要创建NSThread的对象
// 与手动开启线程的方法相比,target 和 selector 两个参数顺序颠倒
[NSThread detachNewThreadSelector:@selector(sayHello:) toTarget:self withObject:@"说你好!"];
} - (void)sayHello:(NSString *)hello {
NSLog(@"%@", hello);
// 打印当前线程
NSLog(@"当前线程:%@", [NSThread currentThread]);
NSLog(@"主线程:%@", [NSThread mainThread]);
}Thread自动开辟子线程
- 开辟子线程成功
- 其他方法
- 注意:
- 每个线程都维护着与自己对应的NSAutoreleasePool对象,将其放在线程栈的栈顶。当线程结束时,会清空自动释放池。
- 为保证对象的及时释放,在多线程方法中需要添加自动释放池。
- 在应用程序打开的时候,系统会自动为主线程创建一个自动释放池。
- 我们手动创建的子线程需要我们手动添加自动释放池。
四、NSObject实现异步后台执行
- (void)viewDidLoad {
#pragma mark - NSObject开辟子线程
/**
* 开启线程的方式之二:NSObject
*/
// 使用performSelectorInBackground开辟子线程
// 参数1:方法
// 参数2:要传的参数
[self performSelectorInBackground:@selector(sayHello:) withObject:@"说你好!"];
self.view.backgroundColor = [UIColor yellowColor];
}
- (void)sayHello:(NSString *)hello {
NSLog(@"%@", hello);
// 打印当前线程
NSLog(@"当前线程:%@", [NSThread currentThread]);
NSLog(@"主线程:%@", [NSThread mainThread]);
// 回到主线程修改view的背景颜色
// 参数1:方法
// 参数2:要传的参数
// 参数3:是否等待子线程完成后再进入主线程
[self performSelectorOnMainThread:@selector(changeColor) withObject:nil waitUntilDone:NO];
}
- (void)changeColor {
self.view.backgroundColor = [UIColor cyanColor];
// 打印当前线程
NSLog(@"==当前线程:%@", [NSThread currentThread]);
NSLog(@"==主线程:%@", [NSThread mainThread]);
}
NSObject异步后台执行,开辟子线程
开辟子线程成功
NSThread和NSObject结合使用:同步请求延迟加载图片
@interface ViewController ()
/// 声明一个ImageView用来显示图片
@property (nonatomic, strong) UIImageView *showImageView;
/// 声明一个NSData类型的数据用于接收图片的数据
@property (nonatomic, strong) NSData *imageData;
@end @implementation ViewController - (void)viewDidLoad {
[super viewDidLoad];
// 创建imageView
_showImageView = [[UIImageView alloc] initWithFrame:CGRectMake(, , , )];
_showImageView.backgroundColor = [UIColor greenColor];
[self.view addSubview:_showImageView]; } #pragma mark - 触发子线程去加载数据
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
[self performSelectorInBackground:@selector(loadImageData) withObject:nil];
} // 加载图片数据
- (void)loadImageData {
NSLog(@"当前线程:%@", [NSThread currentThread]);
NSLog(@"主线程:%@", [NSThread mainThread]);
NSURL *url = [NSURL URLWithString:@"http://img4q.duitang.com/uploads/item/201506/13/20150613185209_nHy5E.jpeg"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
self.imageData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
// 创建主线程用于刷新UI
[self performSelectorOnMainThread:@selector(renovateUI) withObject:nil waitUntilDone:YES]; } // 主线程刷新UI
- (void)renovateUI {
// 安全判断
if ([NSThread mainThread]) {
_showImageView.image = [UIImage imageWithData:self.imageData];
}
}
@end
同步请求实现延迟加载图片
点击触发事件,开辟子线程成功,在主线程中刷新UI,图片显示成功
五、NSOperation和NSOperationQueue
- NSOperation
- NSOperation类,在MVC中属于M,是用来封装单个任务相关的代码和数据的抽象类
- 因为它是抽象的,不能够直接使用这个类,而是使用子类( NSInvocationOperation或NSBlockOperation )来执行实际任务。
- NSOperation(含子类),只是一个操作,本身无主线程、子线程之分,可在任意线程中使用。通常与NSOperationQueue结合使用。
- NSInvocationOperation
- NSInvocationOperation是NSOperation的子类
- 封装了执行操作的target和要执行的action。
- (void)viewDidLoad {
/**
* NSOperation不能直接进行多线程的创建,需要借助:NSOperationQueue。
NSOperation的子类本身和多线程没有任何关系,它只是封装了一定的代码段和数据去实现一个功能。
在单独使用NSOperation的子类去创建线程的时候,实际上线程没有真正被创建。
*/
// 使用NSOperation的第一个子类去创建子线程 -- NSInvocationOperation
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(sayHello:) object:@"
UI进阶 多线程的更多相关文章
- UI进阶 科大讯飞(2) 语音合成(文字转换成语音)
科大讯飞开放平台.SDK下载.添加静态库.初始化见UI进阶 科大讯飞(1) 语音听写(语音转换成文字) 实现语音合成 功能实现步骤: 导入头文件 创建文字识别对象 指定文字识别后的回调代理对象 开启文 ...
- android UI进阶之用【转】
android UI进阶之用ViewPager实现欢迎引导页面 摘要: ViewPager需要android-support-v4.jar这个包的支持,来自google提供的一个附加包.大家搜下即可. ...
- UI进阶 即时通讯之XMPP好友列表、添加好友、获取会话内容、简单聊天
这篇博客的代码是直接在上篇博客的基础上增加的,先给出部分代码,最后会给出能实现简单功能的完整代码. UI进阶 即时通讯之XMPP登录.注册 1.好友列表 初始化好友花名册 #pragma mark - ...
- Android进阶——多线程系列之Thread、Runnable、Callable、Future、FutureTask
多线程一直是初学者最抵触的东西,如果你想进阶的话,那必须闯过这道难关,特别是多线程中Thread.Runnable.Callable.Future.FutureTask这几个类往往是初学者容易搞混的. ...
- UI:多线程 、用GCD创建线程
什么是应用(程序):就是我们编写的代码编译后生成的app文件 进程:凡是一个运行的程序都可以看作为一个进程,如打开的多个 word,就可以认为是一个进程的多个线程. 线程:至少有一个线程就是主线程,网 ...
- Android进阶——多线程系列之异步任务AsyncTask的使用与源码分析
AsyncTask是一种轻量级的异步任务类,它可以在线程池中执行后台任务,然后把执行的进度和最终结果传递给主线程并主线程中更新UI,通过AsyncTask可以更加方便执行后台任务以及在主线程中访问UI ...
- UI进阶
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...
- iOS开发——UI进阶篇(十五)Quartz2D介绍
一.Quartz2D简介 1.什么是Quartz2DQuartz 2D是一个二维绘图引擎,同时支持iOS和Mac系统 Quartz 2D能完成的工作绘制图形 : 线条\三角形\矩形\圆\弧等绘制文字绘 ...
- iOS开发——UI进阶篇(七)程序启动原理、打电话、发短信
一.Info.plist常见的设置 1.建立一个工程后,会在Supporting files文件夹下看到一个“工程名-Info.plist”的文件,该文件对工程做一些运行期的配置,非常重要,不能删除 ...
随机推荐
- HeadFirst设计模式之状态模式
一. 1. 2.The State Pattern allows an object to alter its behavior when its internal state changes. Th ...
- 两个基于C++/Qt的开源WEB框架
1.tufao 项目地址: https://github.com/vinipsmaker/tufao 主页: http://vinipsmaker.github.io/tufao/ 介绍: Tufão ...
- CentOS7.1 JDK安装 和 CentOS7.1配置yum源
1.卸载自带OPENJDK #查看自身jdk java -verson #查看自身安装的java rpm -qa | grep java #显示如下 python-javapackages-3.4. ...
- Git教程(7)用合并还是变基?
合并或变基前的样子:分支experiment与master两个分支都产生了提交. 图1. 未合并或变基前的样子 合并 原理: 找到两个分支的最末提交和最近的共同祖先,在执行git merge时所处的分 ...
- 工具----IcoFX
IcoFX IcoFX 是一款免费的图标编辑工具,让您轻松创建 Windows XP 和 Windows Vista 图标. 在编辑区您可以轻松的预览.保存.更改您的图标.您可以将您喜欢的图像转换为图 ...
- Android开发之ListView-SimpleAdapter的使用
SimpleAdapter: SimpleAdapter(Context context, List<? extends Map<String, ?>> data, int r ...
- [转] Android自动测试之monkeyrunner工具(二)
monkeyrunner工具 前言: 最近开始研究Android自动化测试方法,对其中的一些工具.方法和框架做了一些简单的整理,其中包括android测试框架.CTS.Monkey.Monkeyru ...
- 深入理解Java虚拟机 - 垃圾收集算法与垃圾收集器
1. 垃圾收集算法 JVM的垃圾收集算法在不同的JVM实现中有所不同,且在平时工作中一般不会深入到收集算法,因此只对算法做较为简单的介绍. 1.1 标记-清除算法 ...
- bzoj1025: [SCOI2009] 游戏 6
DP. 每种排法的长度对应所有循环节长度的最小公倍数. 所以排法总数为和为n的几个数的最小公倍数的总数. #include<cstdio> #include<algorithm> ...
- 几种通讯协议的比较RMI > Httpinvoker >= Hessian >> Burlap >> web service
一.综述本文比较了RMI,Hessian,Burlap,Httpinvoker,web service等5种通讯协议的在不同的数据结构和不同数据量时的传输性能.RMI是java语言本身提供的远程通讯协 ...