iOS runloop 自定义输入源
创建自定义输入源需要定义以下内容

上图的处理流程:主线程(Main Thread)发起任务(Task)给工作线程(Worker Thread),主线程会给命令缓冲区(send command-->Command Buffer),通知输入源(signal source-->Input Source),并唤醒工作线程(Wake Up-->Worker Thread)。工作线程收到唤醒命令,Run Loop会调用输入源的处理程序,由它来执行命令缓冲区中相应的命令。
@interface RunLoopSource : NSObject
{
CFRunLoopSourceRef runLoopSource;
NSMutableArray* commands;
}
- (id)init;
- (void)addToCurrentRunLoop;
- (void)invalidate;
// handlermethod
- (void)sourecFired;
// Client interface for registering commands to process
- (void)addCommand:(NSInteger)command withData:(id)data;
- (void)fireAllCommandsOnRunLoop:(CFRunLoopRef)runLoop;
@end
// These are the CFRunLoopSourceRef callback functions.
void RunLoopSourceScheduleRoutine (void *info, CFRunLoopRef rl, CFStringRef mode);
void RunLoopSourcePerformRoutine (void *info);
void RunLoopSourceCancelRoutine (void *info, CFRunLoopRef rl, CFStringRef mode);
// RunLoopContext is a container object used during registration of the input source.
@interface RunLoopContext : NSObject
{
CFRunLoopRef runLoop;
RunLoopSource* source;
}
@property (readonly) CFRunLoopRef runLoop;
@property (readonly) RunLoopSource* source;
- (id)initWithSource:(RunLoopSource*)src andLoop:(CFRunLoopRef)loop;
@end
===当将输入源附加到run loop时,调用这个协调调度例程,将源注册到客户端(可以理解为其他线程)
// Listing 3-4 Scheduling a run loop source
//当source添加进runloop的时候,调用此回调方法 <== CFRunLoopAddSource(runLoop, source, mode);
void RunLoopSourceScheduleRoutine (void *info, CFRunLoopRef rl, CFStringRef mode)
{
RunLoopSource* obj = (RunLoopSource*)info;
AppDelegate* del = [AppDelegate sharedAppDelegate];
RunLoopContext* theContext = [[RunLoopContext alloc] initWithSource:obj andLoop:rl];
[del performSelectorOnMainThread:@selector(registerSource:) withObject:theContext waitUntilDone:NO];
}
===在输入源被告知(signal source)时,调用这个处理例程,这儿只是简单的调用了 [obj sourceFired]方法
// Listing 3-5 Performing work in the input source
//当sourcer接收到消息的时候,调用此回调方法(CFRunLoopSourceSignal(source);CFRunLoopWakeUp(runLoop);
void RunLoopSourcePerformRoutine (void *info)
{
RunLoopSource* obj = (RunLoopSource*)info;
[obj sourceFired];
}
===如果使用CFRunLoopSourceInvalidate/CFRunLoopRemoveSource函数把输入源从run loop里面移除的话,系统会调用这个取消例程,并且把输入源从注册的客户端(可以理解为其他线程)里面移除
// Listing 3-6 Invalidating an input source ==
//当source 从runloop里删除的时候,调用此回调方法 <== CFRunLoopRemoveSource(runLoop, source, mode);
void RunLoopSourceCancelRoutine (void *info, CFRunLoopRef rl, CFStringRef mode)
{
RunLoopSource* obj = (RunLoopSource*)info;
AppDelegate* del = [AppDelegate sharedAppDelegate];
RunLoopContext* theContext = [[RunLoopContext alloc] initWithSource:obj andLoop:rl];
[del performSelectorOnMainThread:@selector(removeSource:) withObject:theContext waitUntilDone:YES];
}
2)安装输入源到Run Loop---分两步首先初始化一个输入源,然后将这个输入源添加到当前Run Loop里面
// List 3-7 Installing the run loop source
- (id)init
{
/*
// Setup the context.
context.version = 0;
context.info = self;
context.retain = NULL;
context.release = NULL;
context.copyDescription = CFCopyDescription;
context.equal = CFEqual;
context.hash = CFHash;
context.schedule = RunLoopSourceScheduleRoutine;
context.cancel = RunLoopSourceCancelRoutine;
context.perform = RunLoopSourcePerformRoutine;
*/
CFRunLoopSourceContext context = {0, self, NULL, NULL, NULL, NULL, NULL,
&RunLoopSourceScheduleRoutine,
&RunLoopSourceCancelRoutine,
&RunLoopSourcePerformRoutine};
runLoopSource = CFRunLoopSourceCreate(NULL, 0, &context);
commands = [[NSMutableArray alloc] init];
return self;
}
- (void)addToCurrentRunLoop
{
CFRunLoopRef runLoop = CFRunLoopGetCurrent();
//Add the new CFRunLoopSourceRef to the indicated runloop, 并且回调RunLoopSourceScheduleRoutine函数
CFRunLoopAddSource(runLoop, runLoopSource, kCFRunLoopDefaultMode);
}
3)协调输入源的客户端(将输入源注册到客户端)
输入源的主要工作就是将与输入源相关联的线程置于休眠状态,直到有事件发生。要达到这个目的,首先客户端(其他线程)知道有该输入源信息,并且有办法与之通信。
通知客户端关于这个输入源信息的方法之一,就是当该输入源开始安装到你的run loop上面后发送注册请求给相关的客户端,该输入源可以注册到任意数量的客户端
也可以通过由代理将输入源注册到感兴趣的客户端
===下面显示了应用委托(AppDelegate)定义的注册方法及从应用委托(AppDelegate)中移除的方法
- (void)registerSource:(RunLoopContext *)sourceInfo
{
NSMutableArray *sourceToPing;
[sourceToPing addObject:sourceInfo];
}
- (void)removeSource:(RunLoopContext *)sourceInfo
{
id objToRemove = nil;
NSMutableArray *sourceToPing;
for(RunLoopContext *context in sourceToPing)
{
if([context isEqual:sourceInfo])
{
objToRemove = context;
break;
}
}
if(objToRemove)
{
[sourceToPing removeObject:objToRemove];
}
}
注:上面两个函数分别在RunLoopSourceScheduleRoutine/RunLoopSourceCancelRoutine函数中被调用
4)通知输入源---客户端(其他线程)发数据到输入源,分两步首先发信号给输入源(signal source),然后唤醒输入源的run loop
===下面显示了客户端发送数据到输入源的方法,在本例中这个方法被放在RunLoopSource对象里面
// Listing 3-9 Waking up the run loop
- (void)fireAllCommandsOnRunLoop:(CFRunLoopRef)runLoop
{
//当手动调用此方法的时候,将会触发 RunLoopSourceContext的performCallback
CFRunLoopSourceSignal(runLoopSource);
CFRunLoopWakeUp(runLoop);
}
注:1,输入源就是一类事件(命令)处理机制。他是线程间的事件(命令)异步通讯机制,所以不能试图通过这个机制实现进程间的通讯。
2,因为CFRunLoopWakeUp函数不是信号安全的,所以对run loop的唤醒,不能在应用信号处理例程(RunLoopSourcePerformRoutine)里面使用。
iOS runloop 自定义输入源的更多相关文章
- run loop 输入源
做了一年多的IOS开发,对IOS和Objective-C深层次的了解还十分有限,大多还停留在会用API的级别,这是件挺可悲的事情.想学好一门语言还是需要深层次的了解它,这样才能在使用的时候得心应手,出 ...
- ios runloop学习
今天突然才之间才意识到NSTimer这样的运行方式,是在多线程中实现的循环还是在主线程中去实现的呢.当然不可能是在主线程中的while那么简单,那样什么都干不了,简单看了下NSTimer是以同步方式运 ...
- 修改VCL源码实现自定义输入对话框
来自:https://yq.aliyun.com/wenji/88428 通过修改VCL源码实现自定义输入对话框 在BCB中有两个函数可以实现输入对话框:InputBox和InputQuery,其实I ...
- iOS Runloop理解
一.RunLoop的定义 当有持续的异步任务需求时,我们会创建一个独立的生命周期可控的线程.RunLoop就是控制线程生命周期并接收事件进行处理的机制. RunLoop是iOS事件响应与任务处理最核心 ...
- iOS RunLoop详解
1. RunLoop简介 1.1 什么是RUnLoop 可以理解为字面的意思:Run表示运行,Loop表示循环.结合在一起就是运行的循环.通常叫做运行循环. RunLoop实际上是一个对象,这个对象在 ...
- iOS runLoop 原理多线程 总结 NSTimer优化
可以理解为字面意思:Run 表示运行,Loop 表示循环.结合在一起就是运行的循环的意思.哈哈,我更愿意翻译为『跑圈』.直观理解就像是不停的跑圈. RunLoop 实际上是一个对象,这个对象在循环中用 ...
- iOS RunLoop简介
一.什么是RunLoop? RunLoop是运行循环,每个Cocoa应用程序都由一个处于阻塞状态的do/while循环驱动,当有事件发生时,就把事件分派给合适的监听器,如此反复直到循环停止.处理分派的 ...
- IOS RunLoop浅析 二
上一篇我们说了runloop 的几种模式,那么我们在模式中又要做些什么呢??? 模式中有三个模块: 事件源(输入源) Source Source: 按照官方文档分类 Port-Based Custom ...
- [转载]SharePoint 2013搜索学习笔记之自定义结果源
搜索中心新建好之后在搜索结果页上会默认有所有内容,人员,对话,视频这四个结果分类,每个分类会返回指定范围的搜索结果,这里我再添加了部门日志结果分类,搜索这个分类只会返回部门日志内容类型的搜索结果,要实 ...
随机推荐
- [翻译]解读CSS中的长度单位
测量,在WEB设计上是非常重要的.在CSS中有至少10种不同的测量单位.每种单位都有其独特的作用,使用它们,可以使页面,在各种设备上,很好的工作.一旦你熟悉了所有这些单位,你可以更准确地设定元素的大小 ...
- kali rolling 配置网络
一. 在文件系统里找到/etc/network下的interfaces文件,打开后可以看到eth0为dhcp,将其修改为如下形式: # This file describes the network ...
- Graph_Master(连通分量_D_Trajan缩点+dfs)
hdu_2242 题目大意:求将一张无向图(n个点,m条边)移除一条边分为不连通两部分,使得两部分的点权和最接近,若无法分为两部分,则输出impossible. 题解:拿到题面还算清晰,就是先tarj ...
- Android studio 运行模拟器报:Application Installation Failed
前两天笔记本加了个SSD硬盘,原机械硬盘移植到光驱位,硬盘盘符都变了,结果在用android studio 运行以前的程序编译不报错,运行模拟器就会报如下错误. Installation failed ...
- webservice的SOAP代理设置
我们的服务器是可以访问的 设置的代理同样也可以访问 接下来设置代理 接着打开TCP窗口 最后来看数据
- Win10 initluictrl failed问题
问题描述 启动win10之后,所有的软件.快捷方式无法访问,双击之后没有响应但联网正常. 解决方法 win键+S弹出选项框,选择cmd(管理员). 键入命令:netsh winsock reset c ...
- 如何将JS里变量的值赋给文本框
举个栗子: <html><HEAD><script type="text/javascript" language="Javascript1 ...
- JavaScript对象、JSON对象、JSON字符串的区别
一.首先看下什么是JSON JSON:JavaScript Object Natation,JavaScript对象的表现形式,已经发展成一种轻量级的数据交换格式. JavaScript对象的表现形式 ...
- hiho 1323 : 回文字符串 dp
#1323 : 回文字符串 时间限制:10000ms 单点时限:1000ms 内存限制:256MB 描述 给定一个字符串 S ,最少需要几次增删改操作可以把 S 变成一个回文字符串? 一次操作可以在任 ...
- Markdown锚点使用
为了使得博客看起来更加美观,我更倾向于使用索引,但是如何在Markdown使用索引跳到指定位置呢?以下是使用方法: 具体应用场景: (1)文献列表中链接--可以通过锚实现页面内的链接:引用文献中可能需 ...