每个应用程序都有一种接收(Window Server)窗口服务器事件的机制。对于一个Cocoa应用程序,这种机制叫主事件循环(the main event loop)。 进程用NSRunLoop对象接收来自各种源的输入。默认情况下,在OS X的每个线程都有它自己的运行循环,而一个Cocoa应用程序主线程的运行循环叫做主事件循环。主事件循环和非实践循环的区别在于它的输入源(Event source)主要接收来自操作系统的事件。输入源(Event source)是由一个从窗口服务器接收事件的端口和一个存储待处理事件FIFO队列组成。如下图
图1-2主事件循环,事件源
Cocoa应用程序是事件驱动的:它会从队列中的事件,将它分派给适当的对象,并在一件事件处理完后,取下一个事件。有一些例外(如模态事件循环)应用程序继续留在这个模式直到用户退出。下面的部分讲事件调度:介绍应用程序如何获取和分发事件。
应用程序接收事件类型多种多样。 应用程序还可以应对苹果事件(Apple Events),高级进程事件交互如启动Finder和启动服务 。例如当用户双击应用程序图标打开应用程序或双击一个文件,打开文件,一个苹果事件发送到目标应用程序。应用程序会从队列中提取苹果事件,但不会把他们转换成NSEevet对象。而是由程序来直接办理。当应用程序启动时,它会自动注册一些处理事件处理器来处理这些Apple Event。
事件分派:
事件分派总的来就应用程序对象(NSApp)从队列中获取一个事件,并把这个事件转换为NSEvent,再把NSEvent分派到最终的目的地。
上文已经把window server窗口服务器事件存储在事件队列中,那事件分派就讲两件事情,第一队列的工作流程就是怎么把事件从事件队列中取出来,第二从队列中取出的事件是如何分派到对应的View。
首先说事件队列的工作流程:应用程序对象(NSApp)调用nextEventMatchingMask:untilDate:inMode:dequeue:方法在封闭的循环中获取事件。当没有事件的时候,这个循环就阻塞。只有当有新的事件要处理的时,循环才resume。
事件分派:应用程序对象(NSApp)首先把转换后的NSEvent通过sendEvent:方法分派出去,大多数情况下,NSApp向用户动作发生的NSWindow对象发送sendEvent:消息,
这个NSWindow对象会分派NSEvent消息到与用户动作有关的NSView对象,这些NSEvent消息包含描述消息如mouseDown: or keyDown:等
事件消息的类型不同处理流程也不同。如鼠标事件和触点事件,NSWindow对象直接发送事件到用户按下鼠标或手点按钮的View对象上。如键盘事件,NSApp对象会发送键盘事件到关键窗口(key window)中的first responder 对象。图1-3和图1-4说明这些不同一般的传递路径。
有时候目标视图有可能无法处理该事件,这是就把NSEevet传递给它响应链(见响应链)。
图1-4