你了解RunLoop线程保活吗?已封装好,2句代码直接使用

如果你没有了解RunLoop的一些基础,建议你看看这2篇博客,对线程保活本质理解有很大帮助

中高级iOS必备知识点之 RunLoop(一)

源码解读RunLoop,理解以后面试必加分

(温馨提示:这里是一步一步探究,步骤过程比较多,如嫌弃啰嗦,可直接拿后面封装的代码直,2句即可完美使用.)

我们面试中经常遇到很多面试官,问我们关于RunLoop的知识点,可能我们大多数人了解RunLoop,但在项目中,我们真正用到RunLoop还是比较少的,RunLoop其实应用场景还是比较多,比如我们的定时器、线程保活、性能优化、监控应用卡顿.这个博客主要介绍的是'线程保活'

现在的网络请求基本都是用的AFNetworking这个框架,相信大家对它很了解,而它里面就是用RunLoop来控制子线程的生命周期.它会让子线程一直存在内存中不释放,这种好处就是对于我们经常去子线程做事情的话,我们就不必一直去创建-销毁-创建-销毁,这样能很大的提高性能,好处也是多多.

接下来我们来看看怎么能做到控制一个线程的生命周期(也就是线程保活),想让它活多久就多久,想让它什么时候销毁就什么时候销毁.

还是老样子,由简单到复杂,我们创建一个线程,这个用NSThread为例子(也可以用PThread,Operation,GCD都可以)

为了能看到线程是什么时候销毁的,我们可以定一个MyThread,继承NSThread,

@interface MyThread : NSThread

并在.m文件,主要监测线程啥时候销毁.

-(void)dealloc{

    NSLog(@"%s",__func__);

}

这样我们就能很清楚的看到MyThread啥时候销毁:

很清楚,上面的代码执行完NSThread就挂了.所以我们在开发中如果有需要经常在子线程干事情,是不是就是希望这个线程能一直不销毁,这样就避免了一直创建-销毁-创建-销毁.

那我们怎么处理?直接在子线程加一个runloop,因为我们知道在获取runloop的时候,就会创建runloop

还是没能成功,如果你有细看我之前的2篇博客,你会注意到有一点:

如果Mode里面没有任何Source0/Source1/Timer/Observer,RunLoop会立马退出

所以我们只要在runloop里面加上任何一个就能保证线程不退出,那我们立刻试试:

  因为是子线程,我们只用NSDefaultRunLoopMode就行了,不用考虑另一个模式

我们再想想,run方法只是达到了线程保活的功能,真正要执行的应该还是在这个线程上去执行另外的操作.所以我完整的写一个线程保活的例子,如下:

上面就是一个简单的线程保活的例子,其实这个是存在一些弊端的,那我们继续探究一下.

'线程保活'存在的问题再探究

为了代码简洁易懂,我换一个block创建,跟上面的效果是一模一样,便于理解,我先是创建2个控制器的跳转,因为我想看看,控制器销毁的时候,线程会不会也跟着销毁.请看下面的代码:

看控制台很明显,此时并没有达到我们想要的结果,虽然线程确实一直存在,能一直帮我做事情(控制台可以一直输出test),但是我们发现控制器销毁了,而控制器上的线程却没有跟着销毁!我们看不到控制台有输出.那是怎么回事呢?难道出现循环引用?很明显不是!

难道是self.Mythread没有清空?你把self.MyThread = nil;写在VC的dealloc里面,你会发现,线程依然不会销毁!

原因是线程一直没有执行完,它一直卡在[[NSRunLoop currentRunLoop] run]这段代码,所以NSLog(@"---- end ----")也一直没有执行,线程都没有结束,所以它不会销毁.所以如果你想要一个全局的线程,任何页面都可以调用,永远不用销毁的话,那这个线程就能达到这个效果.现在我们想要的效果肯定是在当前页面存在,这个VC销毁的时候,线程也会销毁,我们想控制这个线程的生命周期,想让它销毁它就销毁.那我们继续看看怎么处理.

我们知道线程执行结束,线程就会销毁,只要执行NSLog(@"---- end ----"),就能让线程销毁,所以我们明显的思路就是在VC的dealloc里面停止self.MyThread线程的RunLoop.请看下面的代码.

线程依旧没有销毁.

有可能有的人会认为,这很有可能是执行dealloc说明VC快销毁了,你在快销毁的VC中执行stop方法,是不是来不及呢?那这样,我用按钮执行stop事件.请看下图

此时发现,线程依旧没有销毁(log中没有输出线程的dealloc).

[[NSRunLoop currentRunLoop] run]无限循环;

其实是这个[[NSRunLoop currentRunLoop] run];这个原因导致的,我们先看官方的解释,对于这个方法.

看这个上面红色的翻译大致意思是:这个方法是无限循环的执行runMode:beforeDate,它是很有效的处理一个无限循环的.大概类似

white(1)

{runMode:beforeDate}

所以我们大概知道,这个方法是无限循环也就是关不了,可以理解为死循环.而我们执行的CFRunLoopStop(CFRunLoopGetCurrent()),其实只是停止它无限循环中的一次runMode:beforeDate,因为它会不断创建,所以无法全部停止,所以我们很自然想到用runMode:beforeDate这个方法来尝试解决.

看控制台的输出,我们确实是完成了想用它就用它,不用它就让它销毁的操作,也完成了控制器销毁时候,线程也会销毁.(Stop是一个BOOL值,[NSDate distantFuture]是一个很大的值.)

但是上面的还是不够完美,我们看看同样的代码,假如我们其他操作会不会出现什么问题,比如我们很可能不会点击停止,直接点返回,此时我们也想销毁线程,所以我们想着在VC的dealloc里面调用stop方法试试,请看下面:

看上面的操作,此时应该控制器销毁,而线程依旧还是没有销毁

为什么点击调用stop就可以使线程销毁,而在dealloc里面调用stop就不能使线程销毁?

我们当前这个写法先看一个注意点:waitUntilDone这个传值如果传NO有时候可能导致崩溃,原因如下:

有可能出现的情况

所以上面的参数我改成YES.

而线程不销毁的原因是这样:

再执行到这边的时候,while()里面的条件还是一直是YES,导致还是会一直重复执行里面代码,所以runloop还是会一直运行.所以我们把条件改一下即可: while(!weakSelf.Stop&& weakSelf) 把条件改成这个即可(如果这里用__strong处理可能产生循环引用).

看运行结果,这种操作完美解决!

我们再验证一下之前点击停止的那种模式有没有影响!你会发现又崩了!如下:

原因很简单:点击停止已经调用了stop,RunLoop已经结束了,它已经不能做事情了,只是没有销毁.你返回的时候dealloc又调用了stop,又让它去工作,肯定会出问题的.所以我们只要加一个判断即可:

这下真的完美解决了,如论怎么操作,线程和控制器都会销毁!我们看一下成果:

结果完美展示

这里我们发现很多步骤才出来结果,而且是感觉还有点麻烦,那我们直接封装即可:

线程的封装:

封装用起来就非常容易了.先看执行调用代码,再看封装

封装以后就剩这3句,初始化,调用做事,停止,代码很少,很好用,请看效果:

完美解决了这个问题.请看下面封装代码:(就是把我们之前写的,封装起来了):

到这里,我们基本把要说的都说了,该封装的已经封装了,有需要可以直接拿去调用!

因为理论上控制器销毁了,线程也会跟着销毁,所以控制的dealloc里面应该是不用调用stop,按照这个思路我们直接在GDThread的dealloc里面调用stop方法即可,那封装的线程将变得更简单,只有2步操作即可.,初始化,调用做事!

2句代码完成保活!

拓展--C语言的封装

有上面的封装其实已经可以,用C语言的封装作为了解一下:

只要换了红色圈圈的内容即可,其他的都和原来一样,这里也是可以直接使用.

接下来我会继续努力编写其他博客,您的支持就是我最大的动力!

如果觉得我写得对您有所帮助,请点赞关注我,我会持续更新😄

感谢支持🙏🙏🙏!

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

推荐阅读更多精彩内容