文档章节

iOS主线程与子线程

s
 sj1910
发布于 2016/06/18 20:43
字数 1876
阅读 137
收藏 1
点赞 0
评论 0

一、什么是线程
    主线程: 当我们应用程序运行的时候,系统会自动为我们创建出来一个线程,这个线程交做主线程。
    子线程:程序员用代码手动开始的线程叫做子线程
    线程存在的意义:我们需要把比较耗时的任务,放到子线程进行操作
    **查看所在线程: NSLog(@"所在线程 ===== %d",[NSThread isMainThread]);
    输出结果: 1.主线程 ;0.子线程

二、开辟子线程的三种方法
(一).NSThread
  1.创建
- (void)aa:(UIButton *)btn
{
     threadAction方法里的代码是在子线程中执行的
     object:是想要传到方法中的参数
    NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadAction:) object:self.view];
    手动开启子线程
    [thread start];
    线程里面的任务执行完毕以后,系统会自动把该子线程销毁掉
}
- (void)threadAction:(UIView *)tempView {    
     for (int i = 0; i < 10000; i++) {
     // NSLog(@"%d",i);
    }
注意:
     在子线程里面杜绝刷新UI界面
   //tempView.backgroundColor = [UIColor redColor];
    子线程执行完毕之后,回到主线程
    [self performSelectorOnMainThread:@selector(mainThreadAction:) withObject:tempView waitUntilDone:YES];
}
- (void)viewDidLoad {
    [super viewDidLoad];
注意:在[super viewDidLoad];下面这样写法是错误的,
 self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadAction:) object:self.view];  
  错误原因:
    1.执行完毕后,线程自动销毁,重新执行找不到子线程
    2.执行任务当中,再次开启任务,此时该线程正处于执行的忙碌状态,如果再次开启任务,同样会程序崩溃
    解决办法:如果处于执行状态 或者完成状态,则开启一个新的对象
    // 1.利用NSThread 对象方法
if (self.thread.isExecuting | self.thread.isFinished) {
//      self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(threadAction:) object:self.view];
    }
    // 2.利用NSThread 类方法
    [NSThread detachNewThreadSelector:@selector(threadAction:) toTarget:self withObject:self.view];
    // 3.利用NSObject分类
   [self performSelectorInBackground:@selector(threadAction:) withObject:self.view];或
   //[self.thread performSelectorInBackground:@selector(start) withObject:self.view];
(二).NSOperation
1.NSOperation 是一个抽象类,一般不直接使用该类,而是使用其子类
1>.NSInvocationOperation 是以target action 的方式添加线程执行任务
2>.NSBlockOperation 是以block 回调执行任务
注意:上面这两个类的对象,如果单度使用,任务都是在主线程执行,如果放到**操作队列**中,任务则会在子线程执行
- (void)aa:(UIButton *)btn {
 NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(op1) object:nil];
[op1 start];
NSBlockOperation *blockOP = [NSBlockOperation blockOperationWithBlock:^{
      
    }];
此时是单独使用,是在主线程,且需要手动开启
// 操作队列:
    // 目的:是将操作放到队列中执行任务
    // 任务:在子线程还是主线程,取决于操作队列的初始化方式
    // NSOperationQueue mainQueue 主线程
    // [NSOperationQueue alloc] init 子线程
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
NSInvocationOperation *op2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(op2) object:nil];
// 队列添加操作 无需再调用 [op1 start]; 方法
    // 谁先被添加,谁先被执行,但是执行速度可能有快有慢,但执行顺序永远是先添加的op1先执行,op1 一开始,op2马上开始,无需等待op1结束
    // 线程资源重复利用:op1开启一个线程,op2的时候,会看op1的任务是否执行完毕,如果执行完毕,则会占用op1线程资源执行任务,不再开启新线程,如果op1没有完成,op2则开辟新线程
    // 设置操作队列最大线程数
    [queue setMaxConcurrentOperationCount:1];
    [queue addOperation:op1];
    [queue addOperation:op2];
    [queue addOperation:blockOP];
}

(三)、GCD

这是我们现在开发中最常用的方法
GCD grand central dispatch 宏观中央调度中心(多线程计数优化)
     GCD两个重要概念
     1.队列:
       >1.串行队列
         一、系统主队列
         二、自己创建的串行队列
       >2.并行队列
         一、系统全局队列
         二、自己创建的并行对列
     2.任务:
       >1.同步任务
       >2.异步任务
     任务和队列之间的关系
     1.队列需要存放任务
     2.任务需要到队列中执行
     异步/同步 任务可以放到串行队列,也可以放到并行队列,但是任务是在主线程还是子线程执行,任务的方式是同步还是异步,取决于任务自身以及所在的队列

#pragma mark --- 系统主队列 ---
- (IBAction)mainQueue:(id)sender {
    // 获取系统主队列(串行队列)
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
  // 在系统主队列中添加异步任务,任务是在主线程中执行的,任务的执行方式是同步执行,一个任务开始,第二个任务不会马上开始,需等到第一个任务结束
    // 第一个参数:队列
    // 第二个参数:block任务里面执行的代码
     // 添加任务 async异步任务 sync同步任务
    dispatch_async(mainQueue, ^{
       
    });
    dispatch_async(mainQueue, ^{
      
    });   
    // 经典错误
    // 在主队列中添加同步任务,这个任务需要等上一个任务结束才会执行,而上一个任务(- (void)viewDidLoad {},互相嵌套)永远不会结束,造成两个任务之间互相等待的现象,造成界面真死
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    dispatch_sync(mainQueue, ^{
    
    });
}
#pragma makr --- 自己创建串行队列 ---
- (IBAction)seraialQueue:(id)sender {
    // 自己创建串行队列
    // 第一个参数:队列的标示
    // 第二个参数:决定这个队列是串行队列还是并行队列
    // DISPATCH_QUEUE_SERIAL 串行队列
    // DISPATCH_QUEUE_CONCURRENT 并行队列
    // 在自己创建的串行队列中,添加的异步任务,任务是在子线程执行,任务执行方式是同步的
    dispatch_queue_t serialQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_SERIAL);
    /*
    dispatch_async(serialQueue, ^{
     
    });
    dispatch_async(serialQueue, ^{
     
    });
    */
    在自己创建的串行队列中,添加的同步任务,任务是在主线程执行,任务执行方式是同步的
    dispatch_sync(serialQueue, ^{
    
    });
}
#pragma makr --- 自己创建并行队列 ---
- (IBAction)concurrent:(id)sender {
    // 创建并行队列
    dispatch_queue_t serialQueue = dispatch_queue_create(nil, DISPATCH_QUEUE_CONCURRENT);
     在自己创建的并行队列中,添加的异步任务,任务是在子线程执行,任务执行方式是异步的
    /*
    dispatch_async(serialQueue, ^{
   
    });
    dispatch_async(serialQueue, ^{
 
    });
*/
   // 在自己创建的并行队列中,添加的同步任务,任务是在主线程执行,任务执行方式是同步的
    dispatch_sync(serialQueue, ^{

    });
    dispatch_sync(serialQueue, ^{
   
    });    
}
#pragma makr --- 系统并行(全局)队列 ---
- (IBAction)glabalQueue:(id)sender {
    // 获取全局队列
    // 第一个参数:队列优先级,分为:高 低 默认 后台(默认default)
    dispatch_queue_t gloablaQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    在系统全局队列中添加异步任务,任务是在子线程,执行任务方式异步
    /*
    dispatch_async(gloablaQueue, ^{
     
    });
    dispatch_async(gloablaQueue, ^{
     
    });
*/
     在系统全局队列中添加同步任务,任务是在主线程,执行任务方式同步
    dispatch_sync(gloablaQueue, ^{
    
    });
    dispatch_sync(gloablaQueue, ^{

    });
}
#pragma makr --- 只执行一次 ---
这个在现实开发中用到最多
    // 单例的写法变成使用GCD线程安全锁的形式
    // 只允许一个线程访问该资源,其余的都会被拒绝
    static ViewController *vc = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
vc = [[ViewContrlooer alloc] init];
只会执行一次
    });
     //   return vc;
#pragma makr --- 通信 ---
    // 所谓线程通信:就是在子线程中执行耗时的任务,执行完毕后,回到主线程中刷新UI
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0),^{
     执行耗时任务
dispatch_async(dispatch_get_main_queue(),^{
   刷新UI
 });
#pragma makr --- 延迟- - list text here ---
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(DISPATCH_TIME_NOW * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
    });
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0), ^{
    });
备注:在WWDC 2013中,Apple的团队对NSURLConnection进行了重构,并推出了NSURLSession作为替代作为iOS7中新的网络接口,可以异步请求后,线程也逐渐被弱化,虽然工作中不常会遇到,但作为开发人员遇到还是要会使用。

© 著作权归作者所有

共有 人打赏支持
s
粉丝 0
博文 4
码字总数 9171
作品 0
南京
程序员
iOS查看屏幕帧数工具--YYFPSLabel

学习 YYKit 代码时,发现 ibireme 在项目里加入的一个查看当前屏幕帧数的小工具,效果如下: 挺实用,实现方法也很简单,但是思路特别棒。 这里是Demo: YYFPSLabel 这里我把这个小工具从 中...

yehot
2016/04/05
0
0
iOS按钮倒计时在进入后台不继续计时的处理

iOS程序进入后台后十分钟之内就会被系统kill掉,我想要程序进入后台后仍然运行计时功能,怎么解决呢? 方法一:可以使用记录开始时间和获取当前时间的时间差进行处理 还是直接上代码: 下面的...

云上飞飞
07/06
0
0
iOS Debuger(便捷辅助调试器)

前言 首先写这篇文章之前祝大家周末愉快,然后自我介绍一下,我叫吴海超(WHC)在iOS领域有丰富的开发架构经验Github以后我也会以文章的形式分享具有实战意义的文章给大家,希望能够给大家有所...

WHC
2017/01/15
0
0
iOS开发 网络框架AFNetworking源码(一)

目前iOS开发中使用最多的网络访问框架就是AFNetworking了。作为一个第三方框架,用起来确实比直接使用iOS自带的要方便得多。 AFNetworking在github上可以直接下载。地址为:https://github....

神补刀
2015/08/18
0
0
经过阿里,百度一面,二面后,我总结了50道iOS面试题

前言: 金三银四已经过去,根据统计,很多人都会选择在三月四月跳槽,原因有很多,企业年后会有大量员工离职,员工觉得老公司待遇不怎么样?薪资不够高,想换个新环境等等原因,所以,三月四...

原来是泽镜啊
05/04
0
0
iOS运行回路(RunLoop)总结

首先看两个runloop的示例,来源:http://paste.lisp.org/display/86524 第一个: #include <CoreFoundation/CoreFoundation.h> static void perform(void *info _unused) { printf("hellon"......

于赟
2012/11/01
0
0
iOS多线程编程之一——NSThread线程管理

iOS多线程编程之一——NSThread线程管理 NSTread是iOS中进行多线程开发的一个类,其结构逻辑清晰,使用十分方便,但其封装度和性能不高,线程周期,加锁等需要手动处理。 一、NSThread类方法...

珲少
2015/05/19
0
2
最新名企招聘现场,现场实拍笔试部分

大企面试现场,最新笔试题分享,小编也不断收到网友们投稿(现场笔试实拍) 持续关注:iOS首席鉴黄师,持续输出各大公司iOS面试系列文章,欢迎广大程序猿找我投稿面试中碰到的面试题,我会给...

iOS首席鉴黄师
06/04
0
0
IOS中延时执行的几种方式的比较和汇总

IOS中延时执行的几种方式的比较和汇总 本文列举了四种延时执行某函数的方法及其一些区别。假如延时1秒时间执行下面的方法。 - (void)delayMethod { NSLog(@"execute"); } 1.performSelector...

hanbing94
2015/07/25
0
0
cordova与ios native code交互的原理

很早以前写了一篇博客,总结cordova插件怎么调用到原生代码: cordova调用过程,不过写得太水,基本没有提到原理。最近加深了一点理解,重新补充说明一下 js调用native 下面是我们产品中的代...

Michaelyn
2017/10/23
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

JavaEE——JavaScript

声明:本栏目所使用的素材都是凯哥学堂VIP学员所写,学员有权匿名,对文章有最终解释权;凯哥学堂旨在促进VIP学员互相学习的基础上公开笔记。 JavaScript 内置对象 String对象方法: date对象...

凯哥学堂
12分钟前
0
0
Git 远程代码回滚master

方式一(推荐): git revert commit-id 方式二(不推荐):不推荐原因:推送到线上后,其它开发人员需要重新clone git reset --hard commit-id git push origin HEAD --force...

浮躁的码农
12分钟前
0
0
Elasticesearch学习(7)—— ES查询与Java API的对应关系

1、普通查询 类型 ES查询语句 Java查询实现 结果 查询格式 { "query": { "bool": { "must": [], "must_not": [], "should": [], "filter": [] } }, "from": 0, "size": 10, "sort": [] } Que......

叶枫啦啦
13分钟前
15
0
getElementsByClassName()与getElementById()区别

1.document.getElementsByClassName() 返回的是数组 使用:document.getElementsByClassName("className")[0].innerText='具体内容' 2.document.getElementById() 返回的是单个元素 使用:d......

botkenni
23分钟前
0
0
MyBatis入门

一、安装 <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>x.x.x</version></dependency> 二、从 XML 中构建 SqlSessionFactory String r......

一个yuanbeth
24分钟前
0
0
聊聊spring cloud的LoadBalancerAutoConfiguration

序 本文主要研究一下spring cloud的LoadBalancerAutoConfiguration RibbonAutoConfiguration spring-cloud-netflix-ribbon-2.0.0.RC2-sources.jar!/org/springframework/cloud/netflix/ribb......

go4it
27分钟前
0
0
【转】使用Lombok来优雅的编码

前言 Lombok 是一种 Java™ 实用工具,可用来帮助开发人员消除 Java 的冗长,尤其是对于简单的 Java 对象(POJO)。它通过注解实现这一目的。 正文 添加依赖 在 pom.xml 文件中添加相关依赖:...

HAVENT
29分钟前
0
0
Dubbo 源码解读 —— 可支持序列化及自定义扩展

一、概述 从源码中,我们可以看出来。目前,Dubbo 内部提供了 5 种序列化的方式,分别为 fastjson、Hessian2、Kryo、fst 及 Java原生支持的方式 。 针对不同的序列化方式,对比内容如下: 名...

Ryan-瑞恩
37分钟前
0
0
MySQL内存设置—— MySQL server has gone away

set global max_allowed_packet=268435456

一梦心草
46分钟前
0
0
推导式

列表、集合和字典推导式 列表推导式是Python最受喜爱的特性之一。它允许用户方便的从一个集合过滤元素,形成列表,在传递参数的过程中还可以修改元素。形式如下: [expr for val in collect...

火力全開
51分钟前
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部