进程Process: 已经启动的应用程序叫进程
线程Thread: 一段可执行的代码序列(任务 / 代码)
进程和线程的区别:
1. 从数量角度: 一个进程可以包含至少一个线程[1, x)
2. 从执行任务角度: 进程不执行任务,分配资源(根据不同的操作系统);线程执行任务
主线程:当一个程序启动时,就有一个进程被操作系统(OS)创建,与此同时一个线程也立刻运行,该线程通常叫做程序的主线程(Main Thread),因为它是程序开始时就执行的,如果你需要再创建线程,那么创建的线程就是这个主线程的子线程。
主线程和子线程的责任分工
1. 主线程责任(用户 / 交互):
a. 所有和界面相关的逻辑由主线程执行(UIKit Framework)
b. 响应用户的事件(滚动 / 拖拽 / 点击。。。)
2. 子线程(耗时操作)
a. 下载图片 / 音频文件 / for循环逻辑
Xcode 启动之后成为进程,分配线程的资源
1. 主线程: 1M(内存)
2. 子线程: 512KB(内存)
代码可以启动多少个子线程?
3 ~ 5 个子线程
多线程Multi-Thread:
iOS提供多少个创建子线程技术?
一、pthread
1. pthread(了解)
POSIX Thread(Portable Operation System Interface):可移植的操作系统接口线程
2.特点:
优点: 可移植性
缺点: 基于C语言, 底层; 功能少
Demo04_pthread
分析:
1. 主线程阻塞:有其他的耗时操作占用着主线程
2. 所有的事件 / 任务都会放到队列中(主线程操作的队列叫做主队列); 队列中的任务以FIFO(先进先出)方式响应(执行)
3. 让子线程执行耗时操作不会造成主线程阻塞
二、NSThread
1. NSThread特点:
优点: 基于OC语言;
缺点: 需要管理线程的生命周期、同步、加锁问题,这会导致一定的性能开销
2. 如何使用?
a. 如何创建NSThread 类型的子线程方式(alloc / init)
b. 如何调用NSThread方法, 来判断代码是由主线程还是子线程执行
{number = 1, name = main}
{number = 2, name = (null)}
通过[NSThread currentThread]的返回值判定由主线程还是子线程执行
a. number = 1 -> 主线程
b. number不是1 -> 子线程
Demo01_pthread
<span style="font-size:14px;">//主线程MainThread
- (IBAction)executeTimingOperation:(id)sender {
//创建for循环模拟耗时操作
for (int i=0; i<5000; i++) {
NSLog(@"执行次数:%d", i);
}
}
//<#void *(*)(void *)#>
void *task(void *data){
//验证传参
printf("验证传参:%s", (char *)data);
//耗时操作
for (int i=0; i<20000; i++) {
NSLog(@"执行次数:%d", i);
}
return NULL;
}
//子线程
- (IBAction)executeTimingOperationByPthread:(id)sender {
//1.创建子线程对象
/*
参数一:指定pthread_t类型的子线程地址
参数二:指定线程特定属性(占用内存空间)
参数三:函数声明
参数四:传给上面函数的参数
*/
pthread_t pthread;
char *data = "Hello";
pthread_create(&pthread, NULL, task, data);
//2.把耗时操作给子线程执行
}</span>
Demo02_NSThread
<span style="font-size:14px;">// 1.创建NSThread对象
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(downloadImage:) object:@"Hello"];
//设置子线程的名字
thread.name = @"这是我的子线程";
//3.启动子线程的任务Task
[thread start];
NSLog(@"------由线程执行如下代码:%@", [NSThread currentThread]);</span>
<span style="font-size:14px;">//2.将耗时操作指定给子线程方法(对象)
- (void)downloadImage:(NSString *)string{
//由子线程执行
NSLog(@"由子线程执行如下代码:%@", [NSThread currentThread]);
//让子线程休眠5s
[NSThread sleepForTimeInterval:5];
for (int i=0; i<5; i++) {
NSLog(@"执行次数:%d", i);
if (i == 1) {
//线程退出
[NSThread exit];
}
}
}</span>
Demo03_NSThread下载图片
<span style="font-size:14px;">- (IBAction)downloadImageByNSThread:(id)sender {
//1.NSThreaad对象
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(downloadImage) object:nil];
//2.执行下载逻辑
//3.启动子线程
[thread start];
}
- (void)downloadImage{
//NSString -> NSURL -> NSData -> UIImage
NSString *imageStr = @"http://www.egouz.com/uploadfile/2015/0305/20150305103626911.jpg";
NSURL *imageUrl = [NSURL URLWithString:imageStr];
//如下方法是耗时的操作
NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
UIImage *image = [UIImage imageWithData:imageData];
/*
由子线程回到主线程,赋值给imageView
主线程执行任务优先级高于子线程任务
*/
//子线程回到主线程方式一
[self performSelectorOnMainThread:@selector(returnMainThread:) withObject:image waitUntilDone:YES];
}
- (void)returnMainThread:(UIImage *)image{
NSLog(@"赋值:%@", [NSThread currentThread]);
self.imageView.image = image;
}
</span>
坑:
1. 在Info.plist中添加允许HTTP不安全协议的请求,方式如下
2.和UIKit相关的操作需要从子线程回到主线程(原理)
[selfperformSelectorOnMainThread:@selector(returnMainThread:)withObject:image waitUntilDone:YES];