前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS_RunLoop、Modes、Source、Timer、Observer、主要结构...

iOS_RunLoop、Modes、Source、Timer、Observer、主要结构...

作者头像
mikimo
发布2022-07-20 14:12:19
3810
发布2022-07-20 14:12:19
举报
文章被收录于专栏:iOS开发~

RunLoop为了实现程序不退出,在没有事件处理时休眠,在有事件到来时立刻被唤醒。

充分节省CPU资源,提高程序性能。

我们不能创建/显示管理RunLoop对象,系统会在需要的时候为每个线程创建一个RunLoop对象。

1、概念

管理来自window system、Port objects、NSConnection objects、Timer的事件的对象,如:鼠标和键盘的事件。(NSTimer不是“Input”,触发时不会导致run循环返回)

2、Modes 

RunLoop会在不同的时候被设置为不同的Mode

1)common:modes的组合,可以将source、timers、observers注册到这个set中,他们将在这些mode中共享

2)Default:处理非NSConnection对象的输入源模式(通常主线程是在这个Mode下运行)

3)eventTracking:当以模式跟踪事件时(例如拖拽、滑动事件)

4)modalPanel:当等待模式面板的输入时(如NSSavePanel或NSOpenPanel)

5)tracking:在跟踪控制时

3、item事件

RunLoop  -->  n个Modes  -->  n个<Source/Timer/Observer>

切换Mode需要退出Loop,设置Mode后再进入。为了将不同组的<Source/Timer/Observer>分隔开,让其互不影响。

4、结构

代码语言:javascript
复制
typedef struct __CFRunLoopMode *CFRunLoopModeRef;
struct __CFRunLoopMode {
  CFStringRef _name;            // Mode Name, 例如 @"kCFRunLoopDefaultMode"
  CFMutableSetRef _sources0;    // 一个回调,需要sourceSignal、wakeUp
  CFMutableSetRef _sources1;    // 一个port,一个回调,内核和其他线程交互
  CFMutableArrayRef _observers; // Array
  CFMutableArrayRef _timers;    // Array
  ...
};
struct __CFRunLoop {
  CFMutableSetRef _commonModes;     // Set
  CFMutableSetRef _commonModeItems; // Set<Source/Observer/Timer>
  CFRunLoopModeRef _currentMode;    // Current Runloop Mode
  CFMutableSetRef _modes;           // Set
  ...
};

1、Source:

1)Source0:触摸事件,PerformSelectors。

一个回调,不能主动触发事件。

需要先调用CFRunLoopSourceSignal(source)标记为待处理,

然后调用CFRunLoopWakeUp(runloop)来唤醒RunLoop处理这个事件

2)Source1:基于Port的线程间通信。

一个mach_port、一个回调,用于通过内核和其他线程互相发送消息。能主动唤醒RunLoop

2、Timer:

1个时间、1个回调。加入RunLoop时会注册对应的时间点,到时会被唤醒处理回调

3、Observer:

观察者,包含一个回调。当RunLoop状态发生变化时,会触发回调。可以观察的时间点有:

1)Entry:即将进入Loop

2)BeforeTimer:即将处理Timer

3)BeforeSource:即将处理Source

4)BeforeWaiting:即将进入休眠

5)AfterWaiting:刚从休眠中唤醒

6)Exit:即将退出Loop

如果一个Mode中以上任何一个item都没有,就会退出,不进入循环。

CommonModes:

1个Mode可以将自己标记为Common属性,会将起ModeName添加在RunLoop的_commonModes中。每当RunLoop的内容发送变化时,会将_commonModeItems中的<Source/Observer/Timer>自动同步到具有Common标记的所有Mode里(即_commonModes集合里的)

  • 应用举例:NSTimer

主线程中又两个预置的Model:Defaut和Tracking,被标记为Common属性。

1)将Timer分别加入这两个Mode

2)将Timer加入到顶层RunLoop的_commonModeItems中

5、苹果用RunLoop实现的功能

App启动后 ,系统默认

  • 注册了5个Mode:

1)NS Default RunLoop Mode: App的默认 Mode,通常主线程是在这个 Mode 下运行的。

2)UI Tracking RunLoopMode: 界面跟踪 Mode,用于 ScrollView 追踪触摸滑动,保证界面滑动时不受其他 Mode 影响。

3)UI Initialization RunLoopMode: 在刚启动 App 时第进入的第一个 Mode,启动完成后就不再使用。

4)GS EventReceive RunLoopMode: 接受系统事件的内部 Mode,通常用不到。

5)NSRunLoopCommonModes : 这是一个占位的 Mode,没有实际作用。

  • 注册了两个 Observer ( AutoreleasePool  相关操作)

回调Callout:都是 _wrapRunLoopWithAutoreleasePoolHandler()

第一个 Observer 监视的事件是 

Entry (即将进入Loop),其回调内会调用 _objc_autoreleasePoolPush() 创建自动释放池。

(其 order 是-2147483647,优先级最高,保证创建释放池发生在其他所有回调之前。)

第二个 Observer 监听NSRunLoop运行状态: 

BeforeWaiting (准备进入休眠) 时调用_objc_autoreleasePoolPop() 和 _objc_autoreleasePoolPush() 释放旧的池并创建新池;

Exit (即将退出Loop) 时调用 _objc_autoreleasePoolPop() 来释放自动释放池。

(其 order 是 2147483647,优先级最低,保证其释放池子发生在其他所有回调之后。)

在主线程执行的代码,通常是写在诸如事件回调、Timer回调内的。这些回调会被 RunLoop 创建好的 AutoreleasePool 环绕着,所以不会出现内存泄漏,开发者也不必显示创建 Pool 了。

6、底层架构

苹果官方将整个系统大致划分为上述4个层次:

应用层:包括用户能接触到的图形应用,例如 Spotlight、Aqua、SpringBoard 等。

应用框架层:即开发人员接触到的 Cocoa 等框架。

核心框架层:包括各种核心框架、OpenGL 等内容。

Darwin:即操作系统的核心,包括系统内核、驱动、Shell 等内容,这一层是开源的,其所有源码都可以在 opensource.apple.com 里找到。

7、使用

1)解决NSTimer在ScrollView滑动时不work

[runLoop addTimer :timer forMode : NSDefaultRunLoopCommonMode ]; // 将Timer注册到给定的Mode中

timer firing时:会调用RunLoop中关联的Object的selector

2)保持线程常驻

如:在子线程中的afterDelay不work(子线程不会自动创建RunLoop,导致Timer不工作)

在子线程的代码中:

NSRunLoop *runLoop = [ NSRunLoop currentRunLoop ]; // 不获取就不会主动创建

[runLoop addPort :[ NSMachPort port ] forMode : NSDefaultRunLoopMode ];

[runLoop run ];

参考文献:

深入理解RunLoop

iOS底层原理总结 - RunLoop

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-03-05,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1、概念
  • 2、Modes 
  • 3、item事件
  • 4、结构
  • 5、苹果用RunLoop实现的功能
  • 6、底层架构
  • 7、使用
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档