NSThread/NSOperationQueue/GCD 多线程操作

什么是线程?什么是主线程?什么是子线程?

在我们程序运行期间,每个正在运行的代码段,被称为线程。

程序运行期间,至少有一个线程,该线程为主线程,主要负责刷新UI,比如添加控件,删除控件,更新控件等。

如果遇到耗时的功能,程序中有多个线程,除了主线程,其余的都是子线程。

子线程主要负责,耗时的任务,比如,网络请求,处理大数据等。

iOS 如果遇到多个耗时的任务,或者要求,多个任务同时执行。我们可以使用多线程编程技术,开辟多个线程,把任务放到其他进程中执行。

线程与线程之间独立执行,互不干扰。

//iOS 中多线程方式

一,NSTread   线程类

  1,使用线程类,来开辟线程

 二,NSobject分类方法

 使用场景:只想要一个操作,在开辟的子线程中执行。

[self performSelectorInBackground:@selector(printString;)  withObject:@"分类开辟子线程方法"];

[self performSelectorInBackground:@selector(printString;)  withObject:@"分类开辟子线程方法1"];

[self performSelectorInBackground:@selector(printString;)  withObject:@"分类开辟子线程方法2"];

[self performSelectorInBackground:@selector(printString;)  withObject:@"分类开辟子线程方法3"];

// 在主线程中执行SEL方法,传递参数,方法执行结束之前是否等待    yes 等待  ,no不等待

// @"111"是作为参数传递进 方法printString: 

[self performSelectorOnMainThread:@selector(printString:) withObject:@"111" waitUntilDone:YES];


主线程主要用来接受用户相应的操作,更新UI,因此,我们添加UI,更新UI,以及删除UI的操作,一定要放在主线程中执行。比如:label.text = @"aaa";



// 四 , GCD

GCD属于函数级别的多线程,主要是分配不同功能的队列,提供给用户使用。

因此,我们在使用GCD时,根据需求,选用不同功能的队列解决问题。

//1. gcd 串行队列

- (IBAction)serialQueue:(id)sender

//  何时使用: 当多个任务具有依赖关系的时候。

// 比如:处理用户输入-》网络请求-》处理请求结果 -》登录

//1.创建一个串行队列

dispatch_queue_t queue = dispatch_queue_create("queue",DISPATCH_QUEUE_SERIAL);

//2.添加任务,任务只能是block或者是函数类型

// 两个参数,前面一个是队列名,后面是添加的任务,代码块block

dispatch_async(queue,^{

NSLog(@"%@",[NSThread currentThread];

NSLog(@"I was borned");

});

dispatch_async(queue,^{

NSLog(@"%@",[NSThread currentThread];

NSLog(@"i growed");

});

dispatch_async(queue,^{

NSLog(@"%@",[NSThread currentThread];

NSLog(@"I married");

});

dispatch_async(queue,^{

NSLog(@"%@",[NSThread currentThread];

NSLog(@"You were dead");

});

// 2.全局串行队列是main函数执行所在的主线程的队列,我们称为主队列。主队列是一个全局串行队列,便于用户访问

// 获取主队列

dispatch_queue_t mainQueue = dispatch_get_main_queue();

// 给主队列添加刷新UI的操作

dispatch_async(mainQueue,^{

self.view.backgroundColor = [UIColor redColor];

});

// 并行队列  conCurrentQueue

- (IBAction)conCurrentQueue:(id)sender

{

// 并行队列是一种同时可以有多个任务并发执行的队列

// 使用方式:当多个任务,没有依赖关系,谁先执行,谁后执行,都不重要。

//1. 创建并行队列

dispatch_queue_t currentQueue = dispatch_queue_create("queue",DISPATCH_QUEUE_CONCURRENT);

// 2.提交操作

dispatch_async(currentQueue,^{

NSLog(@"%@",[NSThread currentThread]);

NSLog(@"猴子一 连入游戏");

}

dispatch_async(currentQueue,^{

// block 块内封装的可以是需要执行的任务

NSLog(@"%@",[NSThread currentThread]);

NSLog(@"猴子二 连入游戏");

}

dispatch_async(currentQueue,^{

// block 块内封装的可以是需要执行的任务

NSLog(@"%@",[NSThread currentThread]);

NSLog(@"猴子三 连入游戏");

}

}

// 组提交方式

- (IBAction)group:(id)sender

{

// 什么是组提交方式

// 某些时候,我们需要把一些操作,归为一类操作,比如,链接操作,读取操作。而链接操作和读取操作中,又有多个操作。此时使用组提交方式。

//1、创建一个并行队列

dispatch_queue_t queue1 = dispatch_queue_create("queue1", DISPATCH_QUEUE_CONCURRENT);

//2、创建一个组队列

dispatch_group_t group1 = dispatch_group_create();

//3、提交

dispatch_group_async(group1, queue1, ^{

NSLog(@"玩家1连入游戏");

});

dispatch_group_async(group1, queue1, ^{

NSLog(@"玩家2连入游戏");

});

dispatch_group_async(group1, queue1, ^{

NSLog(@"玩家3连入游戏");

});

dispatch_group_async(group1, queue1, ^{

NSLog(@"玩家4连入游戏");

});

dispatch_group_async(group1, queue1, ^{

NSLog(@"玩家5连入游戏");

});

// 组中通知提交方式,当组中所有其他操作执行完毕后,它才会执行

dispatch_group_notify(group1,queue1,^{

NSLog(@"所有玩家接入完毕,游戏开始");

});

}

// barrier 障碍提交方式

- (IBAction)barrier:(id)sender

{

// barrier 提交方式,其实是把多个操作,划分为两个部分,这两个部分执行方式都是并发执行的。

//  只要多一个barrier 就会划分出来两个部分

//  通常用于前面有多个操作,后面有多个操作,后面部分要等到前面部分执行完毕再执行

//1. 并行执行

dispatch_queue_t queue = dispatch_queue_create("queue",DISPATCH_QUEUE_CONCURRENT);

//2.提交操作

dispatch_async(queue,^{

NSLog(@"网络连接成功");

});

dispatch_async(queue,^{

NSLog(@"用户请求成功“);

});

dispatch_async(queue,^{

NSLog(@"验证用户名密码");

});

// 障碍提交方式

dispatch_barrier_async(queue,^{

NSLog(@"验证完成");

});

dispatch_async(queue,^{

NSLog(@"读取用户数据");

});

}

// after 延迟执行

- (IBAction)after:(id)after{

// 延迟执行,多用于加载图,线程睡眠等使用场景

// 1.从哪个时间点去

// 2. 过几秒后

// 3.提交到哪个队列中

// 4. 执行block

dispatch_after(dispatch_time(DISPATCH_TIME_NOW,(int64_t)(5*NSEC_PER_SEC)) , dispatch_get_main_queue(),^{

self.view.backgroundColor = [UIColor redColor];

// 延迟五秒,把当前控制器所在的视图的背景颜色换为红色

});   

}

// apply 重复提交执行

- (IBAction)apply:(id)sender

{

// 使用场景:有多个任务,需要提交到队列中时,使用apply方式

//1. 把多个任务存储到数组中

NSArray *array = @[@"图片1",@"图片2",@"图片3",@"图片4",@"图片5"];

//2. 提交到一个并行队列中

// 参数1. 数组个数,重复执行次数

// 参数2.提交到哪个队列中

// 参数3.当前执行的次数

dispatch_apply(5,dispatch_get_global_queue(0,0),^(size_t i){

// i从0开始到 5-1

NSLog(@"%@",array[i]);

});

}


// NSOperationQueue 

- (IBAction)operationQueue:(id)sender

{

// 使用场景,当我们有多个任务,都需要放倒子线程中执行时,使用操作队列这种方式,更为高效,队列内部给我们创建了合适的线程数。

//  什么是操作队列? 何时使用操作队列?

// 操作队列事以一个队列,内部提交的是操作对象,队列中可以给我们开辟适当的线程数去解决多个要执行的操作

// 操作队列是以合适的线程数,更加高效地解决需求

// 创建操作对象

NSInvocationOperation *invo1 = [[NSInvovationOperation alloc] initWithTarget:self selector:@selector(printString:) object:@"1111"];

NSInvocationOperation *invo2 = [[NSInvovationOperation alloc] initWithTarget:self selector:@selector(printString:) object:@"2222"];

NSInvocationOperation *invo3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(printString:) object:@"333"];

// 2.以block方式创建对象

NSBlockOperation *bo1 = [NSBlockOperation blockOperationWithBlock:^{

// block 内部填写我们要执行的操作,当该操作对象执行时,会调用block,执行操作

NSLog(@"I");

}];

NSBlockOperation *bo2 = [NSBlockOperation blockOperationWithBlock:^{

// block 内部填写我们要执行的操作,当该操作对象执行时,会调用block,执行操作

NSLog(@"lOVE");

}];

NSBlockOperation *bo3 = [NSBlockOperation blockOperationWithBlock:^{

//block 内部填写我们要执行的操作,当该操作对象执行时,会调用block,执行操作

NSLog(@"You");

}];


// 1. 创建一个操作队列

NSOperationQueue *queue1 = [[NSOperationQueue alloc] init];

// 设置操作队列的最大并发数

queue1.maxConcurrentOperationCount = 3;

// 同一时间点,能够执行的操作数

// 当队列的最大并发数为1时为,串行队列,大于1为并行队列。

// 如何让并行队列中,某些任务按照顺序执行?

//  给任务添加依赖关系

[invo2 addDependency:invo1];

[invo3 addDependency:invoke];

//把操作添加到操作队列里面

//    [queue1 addOperation:invo1];

//    [queue1 addOperation:invo2];

//    [queue1 addOperation:invo3];

//把操作添加到操作队列里面

[queue1 addOperation:bo1];

[queue1 addOperation:bo2];

[queue1 addOperation:bo3];

}


- (IBAction)block:(id)sender {

//  [self printNumber];

[NSThread detachNewThreadSelector:@selector(printNumber)  toTarget:self withObject:nil];

}


- (IBAction)thread:(id)sender {

//1、开辟一个线程

// [NSThread detachNewThreadSelector:@selector(printNumber) toTarget:self withObject:nil];

// 注意: detach 创建的线程,自动执行,通常用于默认执行的操作。

// 2、NSThread 开辟的线程另一种方法  init

NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(printString:) object:@"111" ];

//初始化方法创建的线程,需要我们手动开启,使用start方法

[thread start];

//结束线程

// [thread cancel];

NSLog(@"%@ %ld",[NSThread currentThread],[NSThread isMainThread]);

}

// 打印一个string

- (void)printString:(NSString *)string

{

NSLog(@"%@ %d %@",[NSThread currentThread ],[NSThread isMainThread],string);

}

- (IBAction)cankao:(id)sender {

NSLog(@"aaaaa");

}

//for 循环方法

- (void)printNumber

{

@autoreleasepool {

for (int i = 0; i < 655000000; i++) {

NSLog(@"%d",i);

}

}

}

- (IBAction)sync:(id)sender {

//同步提交方式会等 提交的操作执行完毕后,再执行后面的操作。

//同步提交方式会卡主线程。

dispatch_sync(dispatch_get_global_queue(0, 0), ^{

NSLog(@"%@",[NSThread currentThread]);

for (int i = 0; i < 10; i ++) {

NSLog(@"%d",i);

}

});

NSLog(@"%@",[NSThread currentThread]);

NSLog(@"我在下面我在下面我在下面");

dispatch_sync(dispatch_get_global_queue(0, 0), ^{

NSLog(@"aaaaaaaaa");

});

}

void sum(void *string)

{

//注意传递过来的是什么类型就用什么类型打印。

NSLog(@"%s",string);

}

// 提交函数

- (IBAction)function:(id)sender {

dispatch_async_f(dispatch_get_main_queue(), "aaa", sum);

//获取线程名

dispatch_queue_t queue = dispatch_queue_create("aaa", DISPATCH_QUEUE_CONCURRENT);

const char *name = dispatch_queue_get_label(queue);

NSLog(@"%@",[NSString stringWithUTF8String:(const char *)name]);

}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,922评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,591评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,546评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,467评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,553评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,580评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,588评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,334评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,780评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,092评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,270评论 1 344
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,925评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,573评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,194评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,437评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,154评论 2 366
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,127评论 2 352

推荐阅读更多精彩内容