For anyone interested I decided to implement a subclass of NSObjectController.
Each NSMatrix object is removed from the NIB and replaced with individual
NSRadioButtons. I then add an NSObjectController instance to the NIB for each
NSMatrix replaced and set its class to RadioGroupController. I bind each radio
button’s “value” binding to the appropriate object controller, setting the
“Controller Key” to “selection” and setting the “Model Key Path” to the tag
value (e.g., 1, 2, 3, etc.) previously assigned to cells in the NSMatrix. I
then bind the object controller’s “Content Object” to the original model object
(or its proxy object) and corresponding “Model Key Path” previously used by the
NSMatrix’s “selectedTag” binding. This solution requires no modifications to my
model objects, does not require adding IBOutlets and does not require
subclassing either NSWindowController or NSViewController which I rarely had to
do for the windows or views that previously contained the deprecated NSMatrix
objects. The only other piece to the puzzle is to propagate the value from the
object controller back to the model which is accomplished using code similar to
Tom Dalling’s solution
<http://www.tomdalling.com/blog/cocoa/implementing-your-own-cocoa-bindings/>.
All other bindings such as “enabled” and “hidden” map directly from NSMatrix to
the individual NSRadioButtons so there is nothing needed for these except to
replicate them for each radio button as needed. For brevity here is the gist of
the object controller code I use:
@interface RadioGroupController : NSObjectController
@end
NSString* const kKeyPathPrefix = @"selection.";
@implementation RadioGroupController
- (nullable id) valueForKeyPath:(NSString*) inKeyPath {
if (![inKeyPath hasPrefix:kKeyPathPrefix]) {
return [super valueForKeyPath:inKeyPath];
}
NSUInteger const keyPathLength = inKeyPath.length;
NSUInteger const keyPathPrefixLength = kKeyPathPrefix.length;
if (keyPathLength == keyPathPrefixLength) {
return [super valueForKeyPath:inKeyPath];
}
NSString* const keyPath = [inKeyPath
substringWithRange:NSMakeRange(keyPathPrefixLength, keyPathLength -
keyPathPrefixLength)];
return @([self.content integerValue] == keyPath.integerValue ?
NSOnState : NSOffState);
}
- (void) setValue:(nullable id) inValue forKeyPath:(NSString*) inKeyPath {
if (![inKeyPath hasPrefix:kKeyPathPrefix]) {
return [super setValue:inValue forKeyPath:inKeyPath];
}
NSUInteger const keyPathLength = inKeyPath.length;
NSUInteger const keyPathPrefixLength = kKeyPathPrefix.length;
if (keyPathLength == keyPathPrefixLength) {
return [super setValue:inValue forKeyPath:inKeyPath];
}
if ([inValue integerValue] != NSOnState) {
return;
}
NSString* const keyPath = [inKeyPath
substringWithRange:NSMakeRange(keyPathPrefixLength, keyPathLength -
keyPathPrefixLength)];
[self propagateValue:self.content = @(keyPath.integerValue)
forBinding:NSContentObjectBinding];
}
Thanks everyone for your input,
—kevin
_______________________________________________
Cocoa-dev mailing list ([email protected])
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:
https://lists.apple.com/mailman/options/cocoa-dev/archive%40mail-archive.com
This email sent to [email protected]