1. 程式人生 > >響應者鏈

響應者鏈

響應者鏈是應用事件或動作訊息的響應者物件的連結序列,當給定的響應者物件不處理特定的訊息時,物件將訊息傳遞給鏈中的它的繼任者(即下一個響應者)。這允許響應者物件將處理訊息的責任委託給其他的,通常是更高級別的物件。應用程式工具包自動構造響應者鏈,如下所述,但是您可以使用NSResponder中的setNextResponder:方法將自定義物件插入以作為其中的部分,並且可以使用nextResponder檢查它(或遍歷它)。

一個應用程式可以包含任意數量的響應者鏈,但是在任意時間內只有一個是啟用的。響應者鏈對於事件訊息和操作訊息是不同的,如下文所述。

事件訊息的響應者鏈

幾乎所有的事件訊息都使用單個視窗的響應者鏈——即發生關聯使用者事件的視窗。事件訊息的預設響應鏈以NSWindow

物件首先向其傳遞訊息的檢視開始。焦點事件訊息的預設響應鏈以視窗中的第一個響應開始;滑鼠或觸控板事件的預設響應鏈從使用者事件發生的檢視開始。在上述位置中事件如果不被處理,則會繼續向上層的檢視層次結構傳遞直到視窗本身的NSWindow物件。第一個響應者通常是視窗中的“選中”檢視物件,它的下一個響應者是它的包含檢視(也稱為它的父檢視),以此類推直到NSWindow物件。如果一個NSWindowController物件正在管理視窗,它將成為最終的一個響應者。你可以在NSView物件之間插入其他響應者,甚至在靠近鏈頂端的NSWindow物件上面,這些插入的響應者可以接收事件和操作訊息。如果沒有找到處理事件的物件,在響應鏈中的最後一個響應者將會呼叫noResponderFor:
方法,對於鍵控事件,它只會發出嗶嗶聲。事件處理物件(NSWindow或者NSView的子類)可以重寫該方法去執行必要的其他動作。

動作訊息的響應者鏈

對於動作訊息,應用程式工具包構造了一個更復雜的響應鏈,它根據兩個因素變化:

  • 該程式是否基於文件架構型別,如果不是,它的window是否由NSWindowController管理。
  • 應用程式當前是否顯示一個焦點視窗和一個主視窗

動作訊息的響應者鏈相比事件訊息更復雜,因為為了檢測他們的物件,動作訊息需要有一個更靈活的執行時機制,它們不像事件訊息那樣侷限於單個視窗。

最簡單的例子是一個啟用的非文件型別的視窗沒有相關的面板或二級視窗顯示,即,一個主視窗也是焦點視窗,在這種情況下,響應鏈如下:

  1. 主視窗的第一個響應者和在檢視層次結構上的後續響應者物件
  2. 主視窗自身
  3. 主視窗代理(不需要繼承自NSResponder
  4. 應用程式物件,NSApp
  5. 應用程式物件的代理(不需要繼承自NSResponder

上述響應鏈的圖片展示如圖所示:

圖1 操作訊息的非基於文件的應用程式的Responder chain
這裡寫圖片描述
如上圖所示,NSWindow物件和NSApplication物件給他們的委託一個機會來處理動作訊息,就像他們是響應者一樣,即使一個委託不是正式在響應者鏈中(也就是說,一個視窗或應用程式物件的nextResponder訊息不返回代理)。

當應用程式同時顯示主視窗和焦點視窗時,兩個視窗的響應者鏈都可以包含在動作訊息中。正如在視窗分層和視窗型別中解釋的那樣,主視窗是最前面的文件或應用程式的視窗,主視窗通常也有焦點狀態,這意味著它們是當前使用者輸入的焦點。但是主視窗可以有一個與之關聯的輔助視窗或面板,例如Find面板或顯示文件視窗中選擇的詳細資訊的Info視窗,當這個輔助視窗是使用者輸入的焦點時,它就是焦點視窗。

當應用程式有一個主視窗和一個單獨的焦點視窗顯示時,焦點視窗的響應者鏈將首先對動作訊息進行處理,然後是主視窗的響應者鏈,完整的響應鏈由這些響應者和代理組成:

  1. 焦點視窗的第一個響應者和在檢視層次結構上的後續響應者物件
  2. 焦點物件自己
  3. 焦點物件的代理(無需繼承自NSResponder
  4. 主視窗的第一個響應者和在檢視層次結構上的後續響應者物件
  5. 主視窗自己
  6. 主視窗的代理(無需繼承自NSResponder
  7. 應用程式物件,NSApp
  8. 應用程式物件代理(無需繼承自NSResponder

如上所述,焦點視窗和主視窗的響應者鏈中的全域性應用程式物件相同,並且響應者鏈的代理是主視窗響應者鏈末端的響應者。這種設計適用於其他型別應用程式的響應鏈:基於文件體系結構的響應鏈和使用NSWindowController物件進行視窗管理的響應鏈,在後者下,預設的主視窗響應者鏈由以下響應者和代理組成:

  1. 主視窗的第一個響應者和在檢視層次結構上的後續響應者物件
  2. 主視窗自身
  3. 視窗的NSWindowController物件(繼承自NSResponder
  4. 主視窗代理
  5. 應用程式物件,NSApp
  6. 應用程式物件的代理

下圖顯示使用NSWindowController物件的非基於文件的應用程式的響應鏈。

圖2 帶有NSWindowController物件(操作訊息)的非文件應用程式的Responder chain
這裡寫圖片描述

對於基於文件的應用程式,主視窗的預設響應者鏈由以下響應者和代理組成:

  1. 主視窗的第一個響應者和後續在檢視層次結構上的響應者物件
  2. 主視窗自身
  3. 視窗的NSWindowController物件(繼承自NSResponder
  4. 主視窗代理
  5. NSDocument物件(如果與主視窗代理不同)
  6. 應用程式物件,NSApp
  7. 應用程式物件的代理
  8. 應用程式的文件控制器(是一個NSDocumentController物件,未繼承NSResponder

圖3 展示基於文件應用程式的響應者鏈

圖3 操作訊息的基於文件的應用程式的Responder chain
這裡寫圖片描述

總之,相應鏈總體按如下路徑傳遞:

非文件型別:

First responder -> View hierarchy -> NSWindow -> NSWindowController -> NSWindow delegate -> NSApp -> App delegate

文件型別:

First responder -> View hierarchy -> NSWindow -> NSWindowController -> NSWindow delegate -> NSDocument -> NSApp -> App delegate -> NSDocumentController