将耗时操作放到线程中进行:
1、NSThread
// [NSThread currentThread] 获得当前线程,在开发中经常打印。 所有多线程技术都能使用这个方法
// number == 1 主线程
// number != 1 其他线程,子线程, 次线程
// 将耗时的操作放到子线程执行
// 会开辟一个子线程,并且在子线程执行longTimeOperation方法,后面传递参数
[self performSelectorInBackground:@selector(longTimeOperation) withObject:nil];
// 创建线程方式1
- (void)test1
{
// 实例化一个线程对像
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
// 让线程开始工作,启动线程, 在新开的线程执行run方法
[thread start];
}
// 创建线程方式2
- (void)test2
{
NSLog(@"---%@", [NSThread currentThread]);
[NSThread detachNewThreadSelector:@selector(run:) toTarget:self withObject:@"hello"];
NSLog(@"test2 --- %@", [NSThread currentThread]);
}
// 创建线程方式3
- (void)test3
{
// “隐式”创建线程方式
[self performSelectorInBackground:@selector(run:) withObject:@"cz"];
}
2、pthread
// 声明一个线程变量
pthread_t threadId;
/*
参数:
1. 要开的线程的变量
2. 线程的属性
3. 要在这个子线程执行的函数(任务)
4. 这个函数(任务)需要传递的参数
*/
// pthread_create(,, , <#void *restrict#>)
id str = @"hello";
// id需要转成void *,在ARC里,需要使用__bridge 进行桥联
// 1. 这里只是临时把str对象专程void *在这里临时使用。 不改变这个对象(str)的所有权。
// 2. 把对象的所有权交出去,在这个函数把str转成void *
// 如果使用MRC,这里不需要桥联,可以直接设置这个参数
// ARC自动内存管理,本质是编译器特性。是在程序编译的时候,编译器帮我们在合适的地方添加retain,release,autorelease。
pthread_create(&threadId, NULL, run, (__bridge void *)(str));
// 函数
void *run(void *param)
{
NSString *str = (__bridge NSString *)(param);
// 耗时操作放在这里执行
for (int i = 0; i < 20000; i++) {
NSLog(@"%@----%@", [NSThread currentThread], str);
}
return NULL;
}
GCD:
队列:把任务放到队列里面,队列先进先出的原则,
串行队列:顺序,一个一个执行(必须一个任务执行完了,才能从队列里面取出下一个任务)
并发队列:同时,同时执行很多个任务(可以同时取出很多个任务,只要有线程去执行)
同步sync:不会开新线程
异步async:会开新线程,多线程的代名词
串行队列同步执行:不开线程,在原来线程里面一个一个顺序执行
串行队列异步执行:开一条线程,在这个新线程里面一个一个顺序执行
并发队列异步执行:开多个线程,并发执行(不一定是一个一个)执行
并发队列同步执行:不开线程,在原来线程里面一个一个顺序执行
/**
串行队列:顺序,一个一个执行
同步任务:不会开辟新线程,是在当前线程执行
结果:不开新线程,在当前线程顺序执行
dispatch : 调度,GCD里面函数,都是以dispatch开头的
*/
// 1. 创建一个串行队列
//参数:1. 队列标签 2. 队列的属性
dispatch_queue_t queue = dispatch_queue_create("itcast", DISPATCH_QUEUE_SERIAL);
// 2. 同步执行任务
// 一般只要使用”同步“执行,串行队列对添加的同步任务,会立马执行
dispatch_sync(queue, ^{
NSLog(@"%@", [NSThread currentThread]);
});
/**
串行队列:一个一个执行
异步执行:肯定会开新线程,在新线程执行
结果:只会开一个线程,而且所有任务都在这个新的线程里面执行
*/
// 1. 串行队列
// 下面两种写法是一样的
// dispatch_queue_t queue = dispatch_queue_create("itcast", DISPATCH_QUEUE_SERIAL);
dispatch_queue_t queue = dispatch_queue_create("itcast", NULL);
// 2. 异步执行
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
/**
并发队列:可以同时执行多个任务
同步任务:不会开辟新线程,是在当前线程执行
结果:不开新线程,顺序一个一个执行。
*/
//1. 并行队列
dispatch_queue_t queue = dispatch_queue_create("cz", DISPATCH_QUEUE_CONCURRENT);
// 2. 同步执行任务
for (int i = 0; i < 10; i++) {
dispatch_sync(queue, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
/**
并发队列:可以同时执行多个任务
异步执行:肯定会开新线程,在新线程执行
结果:会开很多个线程,同时执行
*/
//1. 并行队列
dispatch_queue_t queue = dispatch_queue_create("cz", DISPATCH_QUEUE_CONCURRENT);
// 2. 异步执行任务
for (int i = 0; i < 10; i++) {
dispatch_async(queue, ^{
NSLog(@"%@ %d", [NSThread currentThread], i);
});
}
总结:1. 开不开线程,由执行任务方法决定,同步不开线程,异步肯定开线程;
2. 开多少线程,由队列决定,串行 最多 开一个线程, 并发可以开多个线程。 具体开多少个,有GCD底层决定。