线程的基本概念
主线程(UI线程)
- 1.如何获取主线程
- 如果是主线程,那么名称叫做main/number = 1
- 如果不是主线程,那么名称就不叫座main/number != 1
注意:
currentThread代表拿到当前线程,如果但前执行的方法是被主线程执行的,那么拿到的就是主线程,如果不是被主线程执行的,那么拿到的就不是主线程
NSLog(@"%@",[NSThread currentThread]);
//明确的告诉系统,需要拿到主线程
NSLog(@"%@",[NSThread mainThread]);
if([NSThread isMainThread])
{
NSLog(@"当前方法是在主线程中执行的");
}
- 3.在主线程中执行耗时操作
注意
NSLog是非常消耗性能的操作
- 点击button(执行以下耗时操作)同时操作UI控件(TextFiled) 会有卡顿
- (IBAction)btnOnClick:(id)sender
for(int i = 0; i < 1000;i++)
{
//以后开发上架必须把NSLog都去掉
NSLog(@"%i",i);
}
}
耗时操作的处理方法
- 耗时操作放到子线程中执行
- 好处
- 用户点击按钮的时候就有反应
- 可以同时处理耗时操作和用UI控件的事件
多线程
iOS中多线程的实现方案(四种)
- pthread(几乎不用)
- NSThread(偶尔使用)
- OC语言(更加面向对象)
- 线程声明周期:程序员管理
- GCD(取代NSThread,
经常使用
)
- C语言
- 可以充分利用设备的多核
- 线程声明周期:自动管理
- NSOperation(对GCD面向对象的封装)
- 基于GCD(底层是GCD)
- 比GCD多了一些更简单实用的功能
- 使用更加面向对象
- 线程声明周期:自动管理
Pthread的基本使用
- 使用pthread创建子线程,把耗时操作放图子线程中
- 创建一个Pthread就意味着开启了一个子线程(耗时9毫秒占用512kb内存)
- 这时点击button在同时操作UI控件,不会卡顿
//导入头文件
#import <pthread/pthread.h>
void *demo(void *parm)
{
NSLog(@"%@",[NSThread currentThread]);
NSLog(@"%s",parm);
//耗时操作
for(int i = 0; i < 1000;i++)
{
//以后开发上架必须把NSLog都去掉
NSLog(@"%i",i);
}
return NULL;
}
- (IBAction)btnOnClick:(id)sender
{
//1.创建子线程
/*
第1个参数:线程代号(线程对象)
第2个参数:(线程属性)
第3个参数:void *(*)(void *)
返回值(*指针名称)参数列表
void * 相当于OC中的id
第4个参数:给第三个参数传递的值
C语言中的数据类型一般都是以 _t 或者Ref结尾
*/
//pthread_t 中已经包含*,所以不用再打了
pthread_t threadId;
pthread_creat(threadId,NULL,demo,"ln");
}
NSThread的基本使用
方法一:通过alloc init创建子线程
- NSThread是OC的,是fundation框架中(可以使用alloc,init),(耗时9毫秒占用512kb内存)
- 创建线程(使用alloc init需要手动启动start)
- 设置线程名称(name)
- 设置线程的优先级(threadPriority,取值范围0.0~1.0 ,1.0最高,默认0.5)
- 优先级高只是被CPU调度的可能性大,并不一定会先执行
NSThread *thread = [[NSThread alloc] initWihtTarget:self selector:@selector(demo:) objc:@"ln"];
[thread start];
(void) demo(NSString *)str
{
//NSLog(@"%@",[NSThread currentThread]);
//NSLog(@"%@",str);
//耗时操作:1分钟(主线程不会等)
//for(int i = 0; i < 9000;i++)
//{
// //以后开发上架必须把NSLog都去掉
// NSLog(@"%i",i);
//}
for(int i = 0; i < 9000;i++)
{
//优先级高只是被CPU调度的可能性大,并不一定会先执行
NSLog(@"%i__%@",i,[NSThread currentThread]);
}
}
- (IBAction)btnOnClick:(id)sender
{
//1.创建子线程
/*
Target :子线程需要调用谁的方法
selector:被子线程调用的方法
object:调用方法时,给方法传递的参数
*/
//注意:如果线程正在执行,那么系统会自动强引用NSThread
//retained during the execution of the detached thread当线程中的任务执行完毕,系统会自动释放线程,对线程进行一次release操作
NSThread *thread = [[NSThread alloc] initWihtTarget:self selector:@selector(demo:) objc:@"ln"];
//若不设置名称娜默认为null
thread.name = @"子线程1";
//线程的优先级越高,那么被CPU调用的可能性就大
//但并不代表着,优先级的高的一定会先执行
thread.threadPriority = 0.0
//2.启动线程(使用NSThread创建的线程必须手动启动)
[thread start];
//子线程2
NSThread *thread2 = [[NSThread alloc] initWihtTarget:self selector:@selector(demo:) objc:@"ln"];
thread2.name = @"子线程2";
thread2.threadPriority = 1.0;
[thread2 start];
NSLog(@"主线程中当前的操作马上执行完毕了");
}
方法二:通过detach创建子线程
- 创建子线程(通过detach)
- 不需要手动调用start启动线程,系统会自动启动
- 通过detach方法创建子线程是没有返回值的(不能设置名称,优先级)
- 优点:
- 使用简便
- 通过detach,不需要手动调用start启动线程,系统会自动启动
- 缺点
- 不可以进行其他设置
- 通过detach方法创建子线程是没有返回值的
- 应用场景:
- 如果仅仅需要简单的开启一个子线程执行一些操作,不需要对子线程进行其他设置,那么推荐使用detach方法创建线程
NSThread *thread = [NSThread detachNewThreadSelector:(@selector:demo:) toTarget:self withObject:@"ln"];
//系统会自动在后台开启一个子线程,并且会自动启动该线程执行任务
[self performSelectorInBackground:@selector(demo:) wihtObject:@"ln"];