暗影骑士擎bios详解_runloop原理和机制

暗影骑士擎bios详解_runloop原理和机制Runloop什么是Runloop?从字面上讲就是运行循环。它内部就是do-while循环,在这个循环内部不断地处理各种任务。一个线程对应一个RunLoop,主线程的RunLoop默认已经启动,子线程的RunLoop得手动启动(调用run方法)RunLoop只能选择一个Mode启动,如果当前Mode中没有任何Source(Sources0、Sources1)、Timer,那么就直接退

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

 
 
 

Runloop

什么是 Runloop?

  • 从字面上讲就是运行循环。

  • 它内部就是do-while循环,在这个循环内部不断地处理各种任务。

  • 一个线程对应一个RunLoop,主线程的RunLoop默认已经启动,子线程的RunLoop得手动启动(调用run方法)

  • RunLoop只能选择一个Mode启动,如果当前Mode中没有任何Source(Sources0、Sources1)、Timer,那么就直接退出RunLoop

  • 基本的作用就是保持程序的持续运行,处理app中的各种事件。通过runloop,有事运行,没事就休息,可以节省cpu资源,提高程序性能。

Runloop对象

iOS中有2套API来访问和使用RunLoop

  • Foundation:NSRunLoop

  • Core Foundation:CFRunLoopRef

  • NSRunLoop和CFRunLoopRef都代表着RunLoop对象

  • NSRunLoop是基于CFRunLoopRef的一层OC包装,所以要了解RunLoop内部结构,需要多研究CFRunLoopRef层面的API。

Runloop与线程

  • 每条线程都有唯一的一个与之对应的RunLoop对象

  • 主线程的RunLoop已经自动创建好了,子线程的RunLoop需要主动创建

  • RunLoop在第一次获取时创建,在线程结束时销毁

获得RunLoop对象

  • Foundation

[NSRunLoop currentRunLoop]; // 获得当前线程的RunLoop对象

[NSRunLoop mainRunLoop]; // 获得主线程的RunLoop对象

  • Core Foundation

CFRunLoopGetCurrent(); // 获得当前线程的RunLoop对象

CFRunLoopGetMain(); // 获得主线程的RunLoop对象

RunLoop相关类

Core Foundation中关于RunLoop的5个类
CFRunLoopRef
CFRunLoopModeRef
CFRunLoopSourceRef
CFRunLoopTimerRef
CFRunLoopObserverRef

CFRunLoopModeRef

CFRunLoopModeRef代表RunLoop的运行模式。
一个RunLoop包含若干个Mode,每个Mode又包含若干个(set)Source/(array)Timer/(array)Observer

每次RunLoop启动时,只能指定其中一个 Mode,这个Mode被称作CurrentMode

如果需要切换Mode,只能退出Loop,再重新指定一个Mode进入

这样做主要是为了分隔开不同组的Source/Timer/Observer,让其互不影响

mode主要是用来指定事件在运行循环中的优先级的,分为:
•   NSDefaultRunLoopMode(kCFRunLoopDefaultMode):默认,空闲状态
•   UITrackingRunLoopMode:ScrollView滑动时会切换到该Mode
•   UIInitializationRunLoopMode:run loop启动时,会切换到该mode
•   NSRunLoopCommonModes(kCFRunLoopCommonModes):Mode集合
苹果公开提供的Mode有两个:
•   NSDefaultRunLoopMode(kCFRunLoopDefaultMode)
•   NSRunLoopCommonModes(kCFRunLoopCommonModes)

CFRunLoopTimerRef

  • CFRunLoopTimerRef是基于时间的触发器

  • CFRunLoopTimerRef基本上说的就是NSTimer,它受RunLoop的Mode影响

  • GCD的定时器不受RunLoop的Mode影响

CFRunLoopSourceRef

CFRunLoopSourceRef是事件源(输入源)
按照官方文档,Source的分类
Port-Based Sources
Custom Input Sources
Cocoa Perform Selector Sources
按照函数调用栈,Source的分类
Source0:非基于Port的
Source1:基于Port的,通过内核和其他线程通信,接收、分发系统事件

CFRunLoopObserverRef

  • CFRunLoopObserverRef是观察者,能够监听RunLoop的状态改变

  • 可以监听的时间点有以下几个

    • kcfRunLoopEntry(即将进入loop)//1

    • kcfRunLoopBeforeTimers(即将处理timer)//2

    • kcfRunLoopBeforeSources(即将处理source)//4

    • kcfRunLoopBeforeWaiting(即将进入休眠)//32

    • kcfRunLoopAfterWaiting(刚从休眠中唤醒)//64

    • kcfRunLoopExit(即将退出loop)//128

  • 添加Observer

    CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(CFAllocatorGetDefault(), kCFRunLoopAllActivities, YES, 0, ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) {
    NSLog(@"----监听到RunLoop状态发生改变---%zd", activity);
});

// 添加观察者:监听RunLoop的状态
CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode);

// 释放Observer
CFRelease(observer);

RunLoop处理逻辑

  • 通知Observer:即将进入Loop(1)

  • 通知Observer:将要处理Timer(2)

  • 通知Observer:将要处理Source0(3)

  • 处理Source0(4)

  • 如果有Source0,跳到第9步(5)

  • 通知Observer:线程即将休眠(6)

  • 休眠,等待唤醒:(7)

    • Source0(port)。

    • timer启动

    • RunLoop设置的timer已经超时

    • Runloop被外部手动唤醒

  • 通知Observer:线程将被唤醒(8)

  • 处理未处理的时间(9)

    • 如果用户定义的定时器启动,处理定时器事件并重启Runloop。进入步骤2.

    • 如果输入源启动,传递相应的消息。

    • 如果RunLopp被显式唤醒而且时间还没超时,重启RunLoop,进入步骤2.

  • 通知Observer:即将退出Loop

Runloop的应用

  • NSTimer
  • ImageView显示
  • PerformSelector
  • 常驻线程
  • 自动释放池

runloop定时源和输入源

image

image

  • Runloop处理的输入事件有两种不同的来源:输入源(input source)和定时源(timer source)

  • 输入源传递异步消息,通常来自于其他线程或者程序。

  • 定时源则传递同步消息,在特定时间或者一定的时间间隔发生

NSRunLoop的实现机制,及在多线程中如何使用

- 实现机制:回答runloop的基本作用,处理逻辑,前面都有。

- 程序创建子线程的时候,才需要手动启动runloop。主线程的runloop已经默认启动。

- 在多线程中,你需要判断是否需要runloop。如果需要runloop,那么你要负责配置runloop并启动。你不需要在任何情况下都去启动runloop。比如,你使用线程去处理一个预先定义好的耗时极长的任务时,你就可以无需启动runloop。Runloop只在你要和线程有交互时才需要

runloop和线程有什么关系?

- 主线程的run loop默认是启动的。
iOS的应用程序里面,程序启动后会有一个如下的main()函数
( argc,  * argv[]) {
@autoreleasepool {
    return UIApplicationMain(argc, argv, , NSStringFromClass([AppDelegate class]));
}
}
重点是UIApplicationMain()函数,这个方法会为main thread设置一个NSRunLoop对象,这就解释了:为什么我们的应用可以在无人操作的时候休息,需要让它干活的时候又能立马响应。

- 对其它线程来说,runloop默认是没有启动的,runloop只在你要和线程有交互时才需要。

- 在任何一个 Cocoa 程序的线程中,都可以通过以下代码来获取到当前线程的 run loop 。
NSRunLoop *runloop = [NSRunLoop currentRunLoop];

autorelease 对象在什么情况下会被释放?

  • 分两种情况:手动干预释放和系统自动释放
  • 手动干预释放就是指定autoreleasepool,当前作用域大括号结束就立即释放
  • 系统自动去释放:不手动指定autoreleasepool,Autorelease对象会在当前的 runloop 迭代结束时释放
  • kCFRunLoopEntry(1):第一次进入会自动创建一个autorelease
  • kCFRunLoopBeforeWaiting(32):进入休眠状态前会自动销毁一个autorelease,然后重新创建一个新的autorelease
  • kCFRunLoopExit(128):退出runloop时会自动销毁最后一个创建的autorelease

对于runloop的理解不正确的是

A 每一个线程都有其对应的RunLoop
B 默认非主线程的RunLoop是没有运行的
C 在一个单独的线程中没有必要去启用RunLoop
D 可以将NSTimer添加到runloop中
  • 参考答案:C
  • 理由:说到RunLoop,它可是多线程的法定。通常来说,一个线程一次只能执行一个任务,执行完任务后就会退出线程。但是,对于主线程是不能退出的,因此我们需要让主线程即时任务执行完毕,也可以继续等待是接收事件而不退出,那么RunLoop就是关键法宝了。但是非主线程通常来说就是为了执行某一任务的,执行完毕就需要归还资源,因此默认是不运行RunLoop的。NSRunLoop提供了一个添加NSTimer的方法,这个方法是在应用正常状态下会回调。

runloop的mode作用是什么?

mode主要是用来指定事件在运行循环中的优先级的,分为:
•   NSDefaultRunLoopMode(kCFRunLoopDefaultMode):默认,空闲状态
•   UITrackingRunLoopMode:ScrollView滑动时会切换到该Mode
•   UIInitializationRunLoopMode:run loop启动时,会切换到该mode
•   NSRunLoopCommonModes(kCFRunLoopCommonModes):Mode集合
苹果公开提供的Mode有两个:
•   NSDefaultRunLoopMode(kCFRunLoopDefaultMode)
•   NSRunLoopCommonModes(kCFRunLoopCommonModes)
如果我们把一个NSTimer对象以NSDefaultRunLoopMode(kCFRunLoopDefaultMode)添加到主运行循环中的时候, ScrollView滚动过程中会因为mode的切换,而导致NSTimer将不再被调度。当我们滚动的时候,也希望不调度,那就应该使用默认模式。但是,如果希望在滚动时,定时器也要回调,那就应该使用common mode。

请写出NSTimer使用时的注意事项(两项即可)

思路和上一题一样,如果想要销毁timer,则必须先将timer置为失效,否则timer就一直占用内存而不会释放。造成逻辑上的内存泄漏。该泄漏不能用xcode及instruments测出来。 另外对于要求必须销毁timer的逻辑处理,未将timer置为失效,若每次都创建一次,则之前的不能得到释放,则会同时存在多个timer的实例在内存中。
参考答案:
•   注意timer添加到runloop时应该设置为什么mode
•   注意timer在不需要时,一定要调用invalidate方法使定时器失效,否则得不到释放

UITableViewCell上有个UILabel,显示NSTimer实现的秒表时间,手指滚动cell过程中,label是否刷新,为什么?

和上一题一样的思路,如果要cell滚动过程中定时器正常回调,UI正常刷新,那么要将timer放入到CommonModes下,因为是NSDefaultRunLoopMode,只有在空闲状态下才会回调。

为什么 UIScrollView 的滚动会导致 NSTimer 失效?

  • 思路和上一题一样,解决办法有2个,一个是更改mode为NSRunLoopCommonModes(无论runloop运行在哪个mode,都能运行),还有种办法是切换到主线程来更新UI界面的刷新
 //将timer添加到NSDefaultRunLoopMode中
 [NSTimer scheduledTimerWithTimeInterval: target: selector:@selector(timerTick:) userInfo: repeats:];
  //然后再添加到NSRunLoopCommonModes里
   NSTimer *timer = [NSTimer timerWithTimeInterval: target: selector:@selector(timerTick:) userInfo: repeats:];
    [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

在滑动页面上的列表时,timer会暂定回调,为什么?如何解决?

  • 思路和上一题一样

在开发中如何使用RunLoop?什么应用场景?

  • 开启一个常驻线程(让一个子线程不进入消亡状态,等待其他线程发来消息,处理其他事件)

  • 在子线程中开启一个定时器

  • 在子线程中进行一些长期监控

  • 可以控制定时器在特定模式下执行

  • 可以让某些事件(行为、任务)在特定模式下执行

  • 可以添加Observer监听RunLoop的状态,比如监听点击事件的处理(在所有点击事件之前做一些事情)

文章如有问题,请留言,我将及时更正。

作者:谈笑风生Smile
链接:https://www.jianshu.com/p/335a9b19adab
來源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
Jetbrains全家桶1年46,售后保障稳定

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/219622.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 通用邮箱正则表达式[通俗易懂]

    通用邮箱正则表达式[通俗易懂]找了一些门户网站的邮箱格式:新浪:4-16个字符,可使用英文小写、数字、下划线,下划线不能在首尾。搜狐:4-16位,数字、小写字母、点、减号或下划线,小写字母开头。腾讯:由3-18个英文、数字、点、减号、下划线组成。网易:6~18个字符,可使用字母、数字、下划线,需以字母开头。谷歌:您可以使用字母、数字和英文句点,请勿使用除字母(a-z)、数字和英文句号外的其他字符。央视:6~20个字符,包括英…

    2022年9月24日
  • java中数组怎么定义_java中数组的定义

    java中数组怎么定义_java中数组的定义展开全部数组的定义语法有两种:typearrayName[];type[]arrayName;type为Java中的任意数据类62616964757a686964616fe58685e5aeb931333365646364型,包括基本类型和组合类型,arrayName为数组名,必须是一个合法的标识符,[]指明该变量是一个数组类型变量。/***数组的三种定义方法**1.数组类型[]数…

    2022年7月7日
  • 新版大官场–男人是山

    新版大官场–男人是山一部官场小说,写的有点虚无缥缈,不够真实。[@more@]这本小说的写法有点发散,期间有些年份的跨度不够合理,中规中矩,闲时可看看。…

    2022年4月28日
  • Pytest(1)安装与入门[通俗易懂]

    Pytest(1)安装与入门[通俗易懂]pytest介绍pytest是python的一种单元测试框架,与python自带的unittest测试框架类似,但是比unittest框架使用起来更简洁,效率更高。根据pytest的官方网站介绍,它

    2022年7月28日
  • QQ好友界面_qq怎么群发消息给好友列表

    QQ好友界面_qq怎么群发消息给好友列表效果如下:依次为图一图二图三图四主要实现效果:点击主标题显示下拉好友,再点击收起下拉好友;鼠标移到好友上背景颜色改变;选中的好友背景颜色也要改变;代码如下:<!DOCTYPEht

    2022年8月4日
  • 解决windowlocationhref不跳转的 BUG「建议收藏」

    解决windowlocationhref不跳转的 BUG「建议收藏」今晚写了代码发现了一个小BUG,记录下。&lt;form&gt;———&lt;p&gt;&lt;!–下面按钮–&gt;&lt;divclass="footerContainer"&gt;&lt;buttonid="nextStep"onclick="skip()&q

    2022年7月15日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号