iOS runloop
来源:互联网 发布:pdf修改软件绿色版 编辑:程序博客网 时间:2024/05/22 03:06
转载地址: http://www.jianshu.com/p/613916eea37f
iOS runloop
写这篇文章开始之前,我都不知道runloop是什么东西,如果从字面的意思翻译应该是一直循环的跑,怀疑可能和死锁有关系,可是死锁具体是怎么回事,我只是记得有这个说法,也发现了一个自己不懂的知识。
初识runloop
我在网上看了一下@sunnnyxx 关于runloop的视频.了解了一下runloop相关知识,也去网络上看各种关于runloop的讲述。
我们一般程序就是执行一个线程,是一条直线.有起点终点.而runloop就是一直在线程上面画圆圈,一直在跑圈,除非切断否则一直在运行。网上说的比喻很好,直线就像昙花一现一样,圆就像OS,一直运行直到你关机为止。
在我们学习iOS生命周期里面都会存在销毁的过程,但是屏幕好像一直能接收各种指令,感觉很像runloop的功效,好像这些是和顶层UIKit无关,IOS架构最底层是Core OS,我分析应该是苹果封装好了,只是我们看不到源码而已。
为什么要使用runloop
@sunnnyxx 在视频介绍了四个作用:
- 使程序一直运行接受用户输入
- 决定程序在何时应该处理哪些Event
- 调用解耦(对于编程经验为0的完全没搞懂这个意思,解释为Message Queue)
- 节省CPU时间
这段视频我觉得不太适合小白去看,因为好多概念还没有融会贯通,也没有理解透彻。但是既然看了,就得总结一下,至少产生一个树突先,留下一个问号,未来把问号变成叹号。
回到开始的疑问,为什么要使用RunLoop,一般情况下我们是没必要去启动线程的RunLoop,除非需要在一个单独的线程长久的检测某个事件,就像视频里面提到的类似微信的语音功能,见一个RunLoop专门负责监听说话的线程。看需求而定了。
CFRunLoopSource
Source是RunLoop的数据源抽象类,类似IOS中的protocol
RunLoop定义两个Version的Source
- Source0:处理App内部事件,App自己负责管理(触发),如UIEvent,CFSocket
- Source1:由RunLoop和内核管理,Mach port驱动 如CFMach、CFMessage
CFRunLoopObserver
向内部报告RunLoop当前状态的更改 CAAnimation
RunLoopObserver 与 Autorelease Pool
UIKit通过RunLoopObserver在RunLoop两次Sleep间对AutoreleasePool进行pop和push,将这次Loop中产生的Autorelease对象释放。(好像swift中没有关于释放的问题)
CFRunLoopMode
RunLoop在同一时段只能且必须在一种特定Mode下Run
更换Mode时, 需要暂停当前的Loop,然后重启新的Loop
- NSDefalutRunLoopMode 默认状态.空闲状态
- UITrackingRunLoopMode 滑动ScrollView
- UIInitializationRunLoopMode 私有,App启动时
- NSRunLoopCommonModes 默认包括上面第一和第二
UITrackingRunLoopMode 与 NSTimer
默认情况下NSTimer被加入NSDefalutRunLoopMode
如果想NSTimer受到组件或者动画影响 添加到NSRunLoopCommonModes(OC代码如下:)
[[NSRunLoop currentRunLoop]addTimer:timer...forMode:NSRunLoopCommonModes];
swift版代码:
NSRunLoop.currentRunLoop().addTimer(timer, forMode: NSRunLoopCommonModes)
RunLoopMode切换
NSDefaultRunLoopMode->UITrackingRunLoopMode->NSDefalutRunLoopMode
RunLoop的挂起与唤醒
- 制定用于唤醒的
mach_port
端口- 调用
mach_msg
监听唤醒端口,被唤醒前,系统内核将这个线程挂起,停留在mach_msg_trap
- 由另外一个线程(或另一个进程中的某个线程)向内核发送这个端口的msg后,trap状态被唤醒,RunLoop继续开始干活
AFNetWorking 中创建RunLoop
创建一个常驻服务线程的很好方法
[[NSThread currentThread] setName:@"AFNetworking"];NSRunLoop *runloop = [NSRunLoop currentRunLoop];[runLoop addPort:[NSMachPort port] forMode:NSDefalutRunLoopMode]//一直活着[runLoop run];
swift版代码
var loop = NSRunLoop.currentRunLoop()loop.addPort(NSMachPort(), forMode: NSDefaultRunLoopMode)loop.run()
一个TableView延迟加载图片的新思路
[self.avatarImageView performSelector:@selector(serImage:) withObjetc:downloadedImage afterDelay:0 inModes:@[NSDefaultRunLoopMode]] + (NSThread *)networkRequestThread { static NSThread *_networkRequestThread = nil; static dispatch_once_t oncePredicate; dispatch_once(&oncePredicate, ^{ _networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil]; [_networkRequestThread start]; }); return _networkRequestThread;
}
这个代码无法转换成swift,可能是我没想到办法,大家谁找到了请评论,谢谢了。
让Crash的App回光返照 只针对Signal Crash
CFRunLoopRef runloop = CFRunLoopGetCurrent();NSArray *allModes = CFBridgingRelease(CFRunLoopCopyAllModes(runLoop));while(1){ for (NSString *mode in allModes){ CFRunLoopInMode((CFStringRef)mode,0.001,false); }}
RunLoop事件队列
每次运行run loop,你线程的run loop对会自动处理之前未处理的消息,并通知相关的观察者。具体的顺序如下:
- 通知观察者run loop已经启动
- 通知观察者任何即将要开始的定时器
- 通知观察者任何即将启动的非基于端口的源
- 启动任何准备好的非基于端口的源
- 如果基于端口的源准备好并处于等待状态,立即启动;并进入步骤9。
- 通知观察者线程进入休眠
- 将线程置于休眠直到任一下面的事件发生:
- 某一事件到达基于端口的源
- 定时器启动
- Run loop设置的时间已经超时
- run loop被显式唤醒
- 通知观察者线程将被唤醒。
- 处理未处理的事件
- 如果用户定义的定时器启动,处理定时器事件并重启run loop。进入步骤2
- 如果输入源启动,传递相应的消息
- 如果run loop被显式唤醒而且时间还没超时,重启run loop。进入步骤2
- 通知观察者run loop结束。
异步测试
- (BOOL)runUntilBlock:(BOOL(^)())block timeout:(NSTimeInterval)timeout{ __block Boolean fulfilled = NO; void (^beforeWaiting) (CFRunLoopObserverRef observer, CFRunLoopActivity activity) = ^(CFRunLoopObserverRef observer, CFRunLoopActivity activity) { fulfilled = block(); if (fulfilled) { CFRunLoopStop(CFRunLoopGetCurrent()); } }; CFRunLoopObserverRef observer = CFRunLoopObserverCreateWithHandler(NULL, kCFRunLoopBeforeWaiting, true, 0, beforeWaiting); CFRunLoopAddObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode); // Run! CFRunLoopRunInMode(kCFRunLoopDefaultMode, timeout, false); CFRunLoopRemoveObserver(CFRunLoopGetCurrent(), observer, kCFRunLoopDefaultMode); CFRelease(observer); return fulfilled;
}
总结一下
基本上对于RunLoop,我只能说我只有简单的模糊印象,但是不理解,也不太清楚在现实如何使用,因为实践才能知道如何做,真的在脑里形成了树突,希望在未来搞定,研究透彻。看这些代码时候我发现我的基础知识还需要巩固。感谢不相识的孙源。
声明一点:不要只去收藏,去看看代码有没有问题,知识有没有解释错误的,交流学的更快。
- iOS runloop
- iOS runloop
- iOS RunLoop
- iOS runloop
- <iOS>RunLoop
- iOS RUNLOOP
- iOS Runloop
- iOS - RunLoop
- iOS runloop
- iOS--Runloop
- iOS runloop
- iOS - RunLoop
- iOS RunLoop
- iOS RunLoop
- iOS RunLoop
- RunLoop-iOS
- ios-Runloop
- iOS RunLoop
- jdk1.6下使用sardine和jackrabbit-webdav的问题
- [LeetCode]236. Lowest Common Ancestor of a Binary Tree
- 基础架构为什么需要融合
- java assert断言的用法
- MAN Truck
- iOS runloop
- Android Gallery组件实现循环显示图像
- iMindMap Android版中怎样添加导图图标
- dedecms 5.6 创建图片集时 出现 数据保存到数据库附加表 `dede_addonimages` 时出错,请把相关信息提交给
- 文件的写入本地以及删除
- [疯狂Java]监听器的实现:内部(闭包)、反射、外部
- 目标检测——从RCNN到Faster RCNN 串烧
- 108.Which two statements are true regarding the COUNT function? (Choose two.)
- 字符串(一)——String类(String No. 1)