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”的文件,该文件对工程做一些运行期的配置,非常重要,不能删除 ...
随机推荐
- 垃圾收集器GC的种类
堆内存的结构:
- SRM 586 DIV1 L1
可以化简为求n条线段的最大覆盖问题,需要注意的是对于实数而言. #include <iostream> #include <vector> #include <strin ...
- 捉虫记2:windows程序句柄泄露的上下文环境
作为程序员,开发程序是基本功,而调试程序也是必不可少的技能之一.软件在主体功能开发完成后会经历各个阶段的测试,才会被发布.在测试过程中,出现较多的可能就是内存泄漏,句柄泄漏,异常崩溃等属于非功能型的软 ...
- 【转】Ubuntu乱码解决方案(全)
转自:http://www.cnblogs.com/end/archive/2011/04/19/2021507.html ubuntu下中文乱码解决方案(全) 1.ibus输入法 Ubuntu 系统 ...
- android SharedPreferences 使用
除了SQLite数据库外,SharedPreferences也是一种轻型的数据存储方式,它的本质是基于XML文件存储key-value键值 对数据,通常用来存储一些简单的配置信息.其存储位置在/dat ...
- 【HDOJ】1648 Keywords
PE的注意,如果没有满足条件的不输出空格.简单模拟,暴力解. /* */ #include <iostream> #include <sstream> #include < ...
- SQL Server中Delete语句表名不能用别名
delete from TABLEA A where A.FIELD1=10 (ORACLE适用)delete TABLEA from TABLEA A where A.FIELD1=1 ...
- 以CTE表达式实现MSSQL的字符串分割函数
ALTER FUNCTION [dbo].[Split] (@sep varchar(2), @s varchar(512))RETURNS tableASRETURN ( WITH P ...
- PopupWindow-弹窗的界面
1 效果图 2 知识点 PopupWindow(View contentView, int width, int height) //创建一个没有获取焦点.长为width.宽为height,内容为 ...
- PostgreSql字符串函数和操作符
本节描述了用于检查和操作字符串数值的函数和操作符.在这个环境中的字符串包括所有 character, character varying, text 类型的值.除非另外说明,所有下面列出的函数都可以处 ...