【iOS】—— RunLoop线程常驻和线程保活
文章目录
- 没有线程常驻会怎么样?
- 线程常驻
- 线程保活
没有线程常驻会怎么样?
我们一般写一个子线程,子线程执行完分配的任务后就会自动销毁,比如下面这个情况:
我们先重写一下NSThread里面的dealloc方法,打印什么时候会调用dealloc方法。
#import "NSThread+NewDealloc.h"@implementation NSThread (NewDealloc)
- (void)dealloc {NSLog(@"%s", __func__);
}
@end
在ViewController里调用方法:
@implementation FirstViewController- (void)viewDidLoad {[super viewDidLoad];NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(doSomeThing) object:nil];[thread start];
}
- (void)doSomeThing {NSLog(@"%s", __func__);
}
根据打印结果我们可以看到,在子线程执行完任务后线程自动销毁。
而我们有时会需要经常在一个子线程中执行任务,频繁的创建和销毁线程就会造成资源浪费,这时候就要用到RunLoop来使线程长时间存活了
线程常驻
开发应用程序的过程中,如果后台操作十分频繁,比如后台播放音乐、下载文件等等,我们希望这条线程永远常驻内存
我们可以添加一条用于常驻内存的强引用子线程,在该线程的RunLoop下添加一个Sources,开启RunLoop
@interface FirstViewController ()
@property (nonatomic, strong) NSThread *thread;
@end
self.thread = [[NSThread alloc] initWithTarget:self selector:@selector(run1) object:nil];[self.thread start];
- (void)run1 {NSLog(@"----run1-----");/*如果不加这句,会发现runloop创建出来就挂了,因为runloop如果没有CFRunLoopSourceRef事件源输入或者定时器,就会立马消亡。下面的方法给runloop添加一个NSport,就是添加一个事件源,也可以添加一个定时器,或者observer,让runloop不会挂掉*/[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSDefaultRunLoopMode];// 方法1 ,2,3实现的效果相同,让runloop无限期运行下去// 方法2
// [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];// 方法3
// [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantFuture]];[[NSRunLoop currentRunLoop] run];// 测试是否开启了RunLoop,如果开启RunLoop,则来不了这里,因为RunLoop开启了循环。NSLog(@"未开启RunLoop");
}- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {// 利用performSelector,在self.thread的线程中调用run2方法执行任务[self performSelector:@selector(run2) onThread:self.thread withObject:nil waitUntilDone:NO];
}- (void)run2 {NSLog(@"----run2------");
}
无论点击屏幕多少次都不会dealloc线程。
我们必须保证线程不消亡,才可以在后台接受时间处理,所以如果没有实现添加NSPort或者NSTimer,会发现执行完run方法,线程就会消亡,后续再执行touchbegan方法无效。
实现了上面三个方法之一,就可以发现执行完了run方法,这个时候再点击屏幕,可以不断执行test方法,因为线程self.thread一直常驻后台,等待事件加入其中,然后执行。
线程保活
RunLoop的启动和关闭方法在上一篇博客的最后讲过【iOS】—— RunLoop初学
我们直奔主题:
通过以上关于RunLoop启动和关闭的方法分析,我们大概有这样一个思路:
- 我们想要控制RunLoop,就需要使用runMode:beforeDate:方法,因为其他两种方法一个无法停止一个只能依赖超时机制
- CFRunLoopStop() 方法只会结束当前的一次的runMode:beforeDate:方法调用,我们必须再做点什么
针对以上疑问,有以下解答:
- 首先,因为runMode:beforeDate:方法是单次调用,我们需要给它加上一个循环,否则调用一次就over了,和不使用RunLoop的效果大同小异
- 这个循环的条件可以默认设置为YES,当调用stop方法时,执行CFRunLoopStop() 方法并且将循环条件改为NO,就可以使循环停止,RunLoop退出
#import "SecondViewController.h"@interface SecondViewController ()
@property (nonatomic, strong) NSThread *aThread;
@property (nonatomic, assign) BOOL stopped;
@end@implementation SecondViewController- (void)viewDidLoad {[super viewDidLoad];self.view.backgroundColor = [UIColor whiteColor];// 添加一个停止RunLoop的按钮UIButton *stopButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];[self.view addSubview:stopButton];stopButton.frame = CGRectMake(180, 180, 100, 50);stopButton.titleLabel.font = [UIFont systemFontOfSize:20];[stopButton setTitle:@"stop" forState:UIControlStateNormal];stopButton.tintColor = [UIColor blueColor];[stopButton addTarget:self action:@selector(stop) forControlEvents:UIControlEventTouchUpInside];// 用于返回的按钮UIButton *backButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];[self.view addSubview:backButton];backButton.frame = CGRectMake(180, 380, 100, 50);backButton.titleLabel.font = [UIFont systemFontOfSize:20];[backButton setTitle:@"back" forState:UIControlStateNormal];backButton.tintColor = [UIColor orangeColor];[backButton addTarget:self action:@selector(back) forControlEvents:UIControlEventTouchUpInside];self.stopped = NO;__weak typeof(self) weakSelf = self;self.aThread = [[NSThread alloc] initWithBlock:^{NSLog(@"go");[[NSRunLoop currentRunLoop] addPort:[[NSPort alloc] init] forMode:NSDefaultRunLoopMode];while (!weakSelf.stopped) {[[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];}NSLog(@"ok");}];[self.aThread start];
}- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {[self performSelector:@selector(doSomething) onThread:self.aThread withObject:nil waitUntilDone:NO];
}// 子线程需要执行的任务
- (void)doSomething {NSLog(@"%s %@", __func__, [NSThread currentThread]);
}- (void)stop {// 在子线程调用stopif (self.aThread) {// 在子线程调用stop[self performSelector:@selector(stopThread) onThread:self.aThread withObject:nil waitUntilDone:YES];}
}// 用于停止子线程的RunLoop
- (void)stopThread {// 设置标记为NOself.stopped = YES;// 停止RunLoopCFRunLoopStop(CFRunLoopGetCurrent());NSLog(@"%s %@", __func__, [NSThread currentThread]);self.aThread = nil;
}- (void)dealloc {NSLog(@"%s", __func__);
}- (void)back {[self stop];[self dismissViewControllerAnimated:YES completion:nil];
}
@end
需要注意的一点是,如果我们的ViewController已经被销毁了,线程并没有死,这就造成了内存泄漏了。所以我们要注意,在ViewController被dealloc之前,先stop线程。
相关文章:

【iOS】—— RunLoop线程常驻和线程保活
文章目录 没有线程常驻会怎么样? 线程常驻线程保活 没有线程常驻会怎么样? 我们一般写一个子线程,子线程执行完分配的任务后就会自动销毁,比如下面这个情况: 我们先重写一下NSThread里面的dealloc方法,打印…...

Springcloud--docker快速入门
认识docker docker相关操作 1.初识Docker 1.1.什么是Docker 微服务虽然具备各种各样的优势,但服务的拆分通用给部署带来了很大的麻烦。 分布式系统中,依赖的组件非常多,不同组件之间部署时往往会产生一些冲突。在数百上千台服务中重复部署…...

基于AT89C51单片机的电子计数器设计与仿真
点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/87770826 源码获取 主要内容: 设计一个电子计时器,数码管初始显示值为“00”,每隔1s电子秒表加1;秒计数到60时清0&a…...
IT程序员如何面对35岁大龄问题?我从公司老板的角度聊聊
很多从事IT行业的人一想到35岁就很焦虑,担心自己被公司裁员后找不到工作。同时还有家庭责任加身,担心中年失业后晚年生活。作为一位公司老板,我想从我的角度谈一下这个问题。 首先,我本质上不介意我的员工年龄,无论是…...

【计算机专业漫谈】【计算机系统基础学习笔记】W2-2-2 模运算系统和补码表示
利用空档期时间学习一下计算机系统基础,以前对这些知识只停留在应试层面,今天终于能详细理解一下了。参考课程为南京大学袁春风老师的计算机系统基础MOOC,参考书籍也是袁老师的教材,这是我的听课自查资料整理后的笔记 补码表示法…...
vue概述
vue2和vue3的区别 vue2和vue3区别 NOvue2vue31 optinos Api写法 比较分散 Compostiton Api 代码集 2重写数序双向绑定通过Object.defineProperty()实现 基于Proxy实现 对数组有了更好的支持 3Fragments 1,在template中只能一个div 2…...

SpringCloud-OpenFeign案例实战
关于Spring Cloud Open Feign的介绍可以参考这两篇博客 OpenFeign服务接口调用 使用Feign作为服务消费者 本博客参考gitee开源项目代码,结合自己的理解,记录下微服务场景下的使用。Talk is cheap. Show me the code! 一、项目结构 这里使用…...

ACM - 数学 - 提高(还没学多少)
ACM - 数学 练习题 一、数论1、分解质因数 :AcWing 197. 阶乘分解2、求约数个数(1)AcWing 1294. 樱花 (求 n!约数个数之和)(2)AcWing 198. 反素数 (求 1 ~ N 中约数最多的…...

JavaScript class和继承的原理
(对于不屈不挠的人来说,没有失败这回事。——俾斯麦) class 相关链接 MDN链接 有关类的详细描述 关于构造函数,原型和原型链的说明 类的概述 类是用于创建对象的模板。他们用代码封装数据以处理该数据。JS 中的类建立在原型上…...

Playwright-python 自动化测试【Anaconda】环境配置
第一步:Anaconda的安装 安装Anaconda的好处,比prenv网速快,并且拥有独立的python环境,再也不用烦恼用哪个python好了。 Anaconda的下载页参见官网下载,Linux、Mac、Windows均支持。 https://mirrors.tuna.tsinghua.ed…...

攻防世界-web-simple js
题目描述:小宁发现了一个网页,但却一直输不对密码。(Flag格式为 Cyberpeace{xxxxxxxxx} ) 打开链接: 然后我们会发现不管我们输入什么密码,发现是都是这样的报错 1. 先用bp抓包看看,可以抓到这样的一串js脚本 看不懂…...
【SpringCloud】初始微服务
目录 一、单体架构 1、概念 2、优点 3、缺点 二、分布式架构 1、概念 2、优点 3、缺点 三、微服务 1、概念 2、优点 3、缺点 四、微服务技术对比 五、SpringCloud 六、服务拆分 1、注意事项 2、服务远程调用 一、单体架构 1、概念 业务的所有功能都集中到一个…...

均摊时间复杂度
均摊时间复杂度,它对应的分析方法,摊还分析(或者叫平摊分析) 均摊时间复杂度应用的场景比它更加特殊、更加有限 // array表示一个长度为n的数组// 代码中的array.length就等于nint[] array new int[n];int count 0;void insert…...

夏驰和徐策的解决数学问题思路——反证法
反证法是一种证明方法,它的基本思路是通过假设某个结论不成立,然后构造出一个矛盾的情况来推导出原先假设的结论是成立的。 具体来说,反证法一般包含以下步骤: 1. 假设所要证明的命题不成立。 2. 通过这个假设,构造…...

面向开发人员的 ChatGPT 提示词教程 - ChatGPT Prompt Engineering for Developers
面向开发人员的 ChatGPT 提示词教程 - ChatGPT Prompt Engineering for Developers 1. 指南(原文: Guidelines)1-1. 提示的指南(原文: Guidelines for Prompting)1-2. 配置1-3. 提示语原则(原文: Prompting Principles)原则 1: 写出清晰而具体的指示(原文: Write clear and spe…...

虹科方案|使用 HK-TRUENAS支持媒体和娱乐工作流程-1
一、摘要 开发和交付能够随时随地触及受众的媒体内容变得越来越重要和复杂。 在当今高度互联、娱乐驱动的世界中,媒体和娱乐 (M&E) 公司需要保持竞争力才能取得成功。 这些组织需要制作各种不同格式的信息和娱乐内容,以便在移动设备、台式机、工作站…...

DDR5内存彻底白菜价,国外大厂却整出了比着火更离谱的骚操作
今年的 PC 硬件市场,似乎出现了明显两极分化现象。 一边是 N、A 两家新显卡价格高高在上,摆明了不坑穷人。 另一边固态硬盘、内存条又在疯狂互卷不断杀价。 四五百元的 2TB SSD,二百元的 16G 内存条早已见怪不怪。 要说面世多年的 PCIe 3.0…...

Linux网络——Shell编程之函数
Linux网络——Shell编程之函数 一、概述二、定义函数的格式1.格式一2.格式二 三、函数的查看和删除1.查看 declare2.删除 declare 四、函数的返回值1.return 返回值2.echo 返回值 五、函数的参数传入与变量范围1.函数的传参2.函数变量的作用范围 六、函数的应用1.阶乘2.递归目录…...
GQCNN+PointNetGPD思路和问题--chatGPT
有很多算法是通过神经网络来预测机械臂抓手的抓取位置,其中一些算法需要点云数据作为输入,例如: PointNetGPD:PointNetGPD是一个端到端的基于点云的抓取姿态检测算法。它使用了一个PointNet架构来处理点云输入,并输出每…...

Mysql索引(2):索引结构
1 概述 MySQL的索引是在存储引擎层实现的,不同的存储引擎有不同的索引结构,主要包含以下几种: 索引结构描述BTree索最常见的索引类型,大部分引擎都支持 B 树索引 Hash索引 底层数据结构是用哈希表实现的, 只有精确匹配索引列的…...

centos 7 部署awstats 网站访问检测
一、基础环境准备(两种安装方式都要做) bash # 安装必要依赖 yum install -y httpd perl mod_perl perl-Time-HiRes perl-DateTime systemctl enable httpd # 设置 Apache 开机自启 systemctl start httpd # 启动 Apache二、安装 AWStats࿰…...
《Playwright:微软的自动化测试工具详解》
Playwright 简介:声明内容来自网络,将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具,支持 Chrome、Firefox、Safari 等主流浏览器,提供多语言 API(Python、JavaScript、Java、.NET)。它的特点包括&a…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...
【AI学习】三、AI算法中的向量
在人工智能(AI)算法中,向量(Vector)是一种将现实世界中的数据(如图像、文本、音频等)转化为计算机可处理的数值型特征表示的工具。它是连接人类认知(如语义、视觉特征)与…...

现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...

【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...

九天毕昇深度学习平台 | 如何安装库?
pip install 库名 -i https://pypi.tuna.tsinghua.edu.cn/simple --user 举个例子: 报错 ModuleNotFoundError: No module named torch 那么我需要安装 torch pip install torch -i https://pypi.tuna.tsinghua.edu.cn/simple --user pip install 库名&#x…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】
大家好,我是java1234_小锋老师,看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】,分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

mac 安装homebrew (nvm 及git)
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...