VCs in the Responder Chain - Again, but with a good solution?
VCs in the Responder Chain - Again, but with a good solution?
- Subject: VCs in the Responder Chain - Again, but with a good solution?
- From: Seth Willits <email@hidden>
- Date: Tue, 11 Feb 2014 16:49:55 -0800
This is one of those topics I thought about 6 years ago, came across a decent easy-to-use solution that has worked fine so I've never really had to think about it again. Until today. <skip long story>
All the way back to when NSViewController was added it was clear that the VC ideally should follow its view within the responder chain, and every once in a while I see someone else's one off little hack, or use-multiple-subclasses-and-call-some-code solution to put the VC next to the view in the chain, but they're all overly complicated so I noodled on a new idea.
In this solution, all you need to do is have the view controllers you want to be in the chain, descend from an NSViewController subclass. That's it. And the implementation is really quite simple. The end result is each view's VC is the view's nextResponder, and the VC's next responder is the view's superview. So it just inserts itself in there nicely.
The only possibility where I can see this being an issue is if something _requires_ the view's nextResponder be its superview. Anybody know of a case where that's what's required? I hope not because this is by far the easiest solution I've seen (though it's quite possible someone's already done exactly this).
I'm optimistic, but braced for a bubble burst.
static int AGChainedViewControllerKVOContext;
@implementation AGChainedViewController
{
// Need to avoid circular loadView/setView: nonsense,
// so we're just keeping around our own ref in parallel.
NSView * _theView;
}
- (void)dealloc;
{
if (_theView) {
[_theView removeObserver:self forKeyPath:@"nextResponder" context:&AGChainedViewControllerKVOContext];
_theView.nextResponder = nil;
[_theView release];
_theView = nil;
}
[super dealloc];
}
- (void)setView:(NSView *)view;
{
if (_theView) {
[_theView removeObserver:self forKeyPath:@"nextResponder" context:&AGChainedViewControllerKVOContext];
[_theView release];
_theView.nextResponder = nil;
_theView = nil;
}
[super setView:view];
if (self.view) {
_theView = [self.view retain];
[_theView addObserver:self forKeyPath:@"nextResponder" options:0 context:&AGChainedViewControllerKVOContext];
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
{
if (context == &AGChainedViewControllerKVOContext) {
if ((object == _theView) && [keyPath isEqual:@"nextResponder"]) {
if (_theView.nextResponder) {
if (_theView.nextResponder != self) {
self.nextResponder = _theView.nextResponder;
_theView.nextResponder = self;
}
} else {
self.nextResponder = nil;
}
return;
}
}
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
@end
--
Seth Willits
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden