簡體   English   中英

如何檢查響應者鏈?

[英]How to inspect the responder chain?

我正在使用基於文檔的架構在單個窗口中處理一些瘋狂的多個文檔,並且我已經完成了 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文檔NSResponder ,這條鏈似乎應該是這樣的:

當前視圖 -> Superview(重復) -> Window -> WindowController -> Document -> DocumentController -> Application。

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

您可以使用NSResponder 的 nextResponder方法遍歷響應者鏈。 對於您的示例,您應該能夠從當前視圖開始,然后重復打印出在循環中調用它的結果,如下所示:

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

這是 Swift 用戶的另一個版本:

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

    print(responder)
    printResponderChain(responder.next)
}

只需使用 self 調用它即可打印出從 self 開始的響應者鏈。

printResponderChain(self)

我將通過使用在調試時感覺更“可用”的類方法(您不需要中斷特定視圖或其他內容)來改進 Responder 類別答案。

代碼適用於 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

您還可以使用適當的方法向 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
    ...
}

迅速:

extension UIResponder {
    var responderChain: [UIResponder] {
        var chain = [UIResponder]()
        var nextResponder = next
        while nextResponder != nil {
            chain.append(nextResponder!)
            nextResponder = nextResponder?.next
        }
        return chain
    }
}

// ...

print(self.responderChain)

這里是最簡單的

    extension UIResponder {
        func responderChain() -> String {
            guard let next = next else {
                return String(describing: self)
            }

            return String(describing: self) + " -> " + next.responderChain()
        }
    }

    // ...

    print(self.responderChain())

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM