2010-11-22 48 views
16

我正在做一些瘋狂的多個文件在單個窗口內的文件爲基礎的架構的東西,我95%完成。如何檢查響應者鏈?

我有這種雙層文檔體系結構,其中父文檔打開並配置窗口,提供「子」文檔列表。當用戶選擇其中一個孩子時,該文檔將使用相同的窗口控制器打開,並在窗口中放置一個NSTextView。窗口控制器的文檔關聯被更改,以便「編輯的點」和窗口標題跟蹤當前選定的文檔。想想一個Xcode項目,以及在編輯其中的不同文件時會發生什麼。

要將代碼置於僞形式,當打開子文檔時,會在父文檔中調用類似這樣的方法。

-(void)openChildDocumentWithURL:(NSURL *)documentURL { 
    // Don't open the same document multiple times 
    NSDocument *childDocument = [documentMapTable objectForKey:documentURL]; 
    if (childDocument == nil) { 
    childDocument = [[[MyDocument alloc] init] autorelease]; 
    // Use the same window controller 
    // (not as bad as it looks, AppKit swaps the window's document association for us) 
    [childDocument addWindowController:myWindowController]; 
    [childDocument readFromURL:documentURL ofType:@"Whatever" error:NULL]; 

    // Cache the document 
    [documentMapTable setObject:childDocument forKey:documentURL]; 
    } 

    // Make sure the window controller gets the document-association swapped if the doc came from our cache 
    [myWindowController setDocument:childDocument]; 

    // Swap the text views in 
    NSTextView *currentTextView = myCurrentTextView; 
    NSTextView *newTextView = [childDocument textView]; 
    [newTextView setFrame:[currentTextView frame]]; // Don't flicker  

    [splitView replaceSubview:currentTextView with:newTextView]; 

    if (currentTextView != newTextView) { 
    [currentTextView release]; 
    currentTextView = [newTextView retain]; 
    } 
} 

這工作,我知道,窗控制器具有在任何給定的時間正確的文件關聯,因爲變化點和標題跟隨我編輯的文件爲準。但是,當我點擊保存時,(CMD + S或文件 - >保存/另存爲),它想要保存父文檔,而不是當前文檔(如[[NSDocumentController sharedDocumentController] currentDocument]報告的那樣,並且如窗口標題和改變點)。

從閱讀NSResponder文檔,好像鏈條應該是這樣的:

當前視圖 - >上海華盈(重複) - >窗口 - > WindowController - >文件 - > DocumentController - >應用程序。

我不確定基於文檔的架構如何設置響應者鏈(即如何將NSDocumentNSDocumentController置入鏈中),所以我想調試它,但我不確定在哪裏尋找。我如何在任何特定時間訪問響應者鏈?

回答

38

您可以使用NSResponder的nextResponder方法遍歷響應者鏈。對於你的榜樣,你應該能夠開始與當前視圖,然後反覆打印出結果,稱這是在這樣的循環:

NSResponder *responder = currentView; 
while ((responder = [responder nextResponder])) { 
    NSLog(@"%@", responder); 
} 
+0

謝謝,我不知道這是怎麼發生在我身上,我非常專注於直接抓取整個堆棧的想法。 – d11wtq 2010-11-22 03:39:21

6

這裏是另一個版本的雨燕用戶:

func printResponderChain(_ responder: UIResponder?) { 
    guard let responder = responder else { return; } 

    print(responder) 
    printResponderChain(responder.next) 
} 

只需用自己的名稱來打印出自己的響應者鏈。

printResponderChain(self) 
3

您還可以使用UIResponder的任何子類可以使用的適當方法向類UIResponder添加一個類別。

@interface UIResponder (Inspect) 

- (void)inspectResponderChain; // show responder chain including self 

@end 

@implementation UIResponder (Inspect) 

- (void)inspectResponderChain 
{ 
    UIResponder *x = self; 
    do { 
     NSLog(@"%@", x); 
    }while ((x = [x nextResponder])); 
} 
@end 

比你可以在代碼中的某處使用此方法,下面的例子:

- (void)viewDidLoad { 
    ... 
    UIView *myView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)]; 
    [self.view addSubview:myView]; 
    [myView inspectResponderChain]; // UIView is a subclass of UIResponder 
    ... 
} 
2

斯威夫特3:

func printResponderChain(from responder: UIResponder?) { 
    var responder = responder 
    while let r = responder { 
     print(r) 
     responder = r.next 
    } 
} 


printResponderChain(from: view) 
1

我會改進的響應類別回答了一下,通過使用一種在調試時感覺更「可用」的類方法(您不需要在特定視圖或其他任何方面打破)。

代碼適用於Cocoa,但應易於移植到UIKit。

@interface NSResponder (Inspect) 

+ (void)inspectResponderChain; 

@end 

@implementation NSResponder (Inspect) 

+ (void)inspectResponderChain 
{ 
    NSWindow *mainWindow = [NSApplication sharedApplication].mainWindow; 

    NSLog(@"Responder chain:"); 
    NSResponder *responder = mainWindow.firstResponder; 
    do 
    { 
    NSLog(@"\t%@", [responder debugDescription]); 
    } 
    while ((responder = [responder nextResponder])); 
} 

@end