The final batch of open source categories: DejalUIKitCategories.
DejalUIKitCategories is a collection of categories for UIKit on iOS, to add useful methods to classes like UIBarButtonItem
, UIColor
, UIView
, and others. The categories include:
UIBarButton
instances based on and image, title, system item, custom view, spacer, or segmented control.You can get the code and more information from the Dejal Open Source page.
(Looking for an iOS or Mac developer? I'm available for contract or full-time work. Learn more about me.)
Another developer post.
I recently released my DejalAppKitCategories open source project, which includes categories for OS X UI classes.
I am currently working on Time Out 2, and wanted to modernize the radio buttons in the preferences. In the AppKit release notes for OS X 10.10, Apple wrote:
Use of NSMatrix is informally deprecated. We expect to add the formal deprecation macros in a subsequent release, but its use is discouraged in the mean time. The primary use of NSMatrix is for radio button groups, so recall that for applications linked on 10.8 or later, radio buttons that share the same parent view and action will operate as a group.
Which is all well and good, but managing a radio group is annoying when using standalone buttons, so I added some methods to help.
These methods are part of my DejalAppKitCategories open source project, in the NSButton+Dejal category.
Here's the header:
@interface NSButton (DejalRadios)
@property (nonatomic, setter=dejal_setRadiosEnabled:) BOOL dejal_radiosEnabled;
- (void)dejal_selectRadioWithTag:(NSInteger)tag;
- (NSInteger)dejal_selectedRadioTag;
- (NSButton *)dejal_radioPassingTest:(BOOL (^)(NSButton *radio, BOOL *stop))predicate;
- (void)dejal_enumerateRadiosUsingBlock:(void (^)(NSButton *radio, BOOL *stop))block;
@end
And the implementation:
@implementation NSButton (DejalRadios)
/**
Assuming the receiver is a radio button, finds other radio buttons in the group (i.e. in the same superview and with the same action) and selects the one with the specified tag. Invoke this on any of the radios in the group. A replacement for -[NSMatrix selectCellWithTag:].
@param tag The tag value to select.
@author DJS 2015-01.
*/
- (void)dejal_selectRadioWithTag:(NSInteger)tag;
{
[self dejal_enumerateRadiosUsingBlock:^(NSButton *radio, BOOL *stop)
{
radio.state = radio.tag == tag;
}];
}
/**
Assuming the receiver is a radio button, finds other radio buttons in the group (i.e. in the same superview and with the same action) and returns the tag value of the selected radio. Invoke this on any of the radios in the group. A replacement for -[NSMatrix selectedTag].
@returns A tag value integer.
@author DJS 2015-01.
*/
- (NSInteger)dejal_selectedRadioTag;
{
NSButton *foundRadio = [self dejal_radioPassingTest:^BOOL(NSButton *radio, BOOL *stop)
{
return radio.state;
}];
return foundRadio.tag;
}
/**
Returns YES if the radio group is enabled, or NO if not. Simply returns the state of the receiver; the others are assumed to be the same. (If you want to know if they are all enabled or disabled, probably best to use -dejal_enumerateRadiosUsingBlock: to scan the group, and handle a mixed case as needed.)
@author DJS 2015-01.
*/
- (BOOL)dejal_radiosEnabled;
{
return self.enabled;
}
/**
Sets all of the radios in the group to be enabled or disabled. A replacement for -[NSMatrix setEnabled:].
@author DJS 2015-01.
*/
- (void)dejal_setRadiosEnabled:(BOOL)enabled;
{
[self dejal_enumerateRadiosUsingBlock:^(NSButton *radio, BOOL *stop)
{
radio.enabled = enabled;
}];
}
/**
Assuming the receiver is a radio button, finds other radio buttons in the group (i.e. in the same superview and with the same action) and performs the block for each of them, passing the radio to the block. Returns the one that returns YES, or nil if the block requests to stop before completion, or it completes without the block returning YES. Invoke this on any of the radios in the group.
@param block A block that takes a radio button and stop boolean reference as parameters and returns a boolean.
@returns The found radio button, or nil if none is found.
@author DJS 2015-01.
*/
- (NSButton *)dejal_radioPassingTest:(BOOL (^)(NSButton *radio, BOOL *stop))predicate;
{
for (NSButton *radio in self.superview.subviews)
{
// There's no reliable way to determine if a button is actually a radio button, but it's reasonable to assume that no non-radio will have the same action (and having the same action is what makes it a member of the group):
if ([radio isKindOfClass:[NSButton class]] && radio.action == self.action && predicate)
{
BOOL stop = NO;
if (predicate(radio, &stop))
{
return radio;
}
if (stop)
{
return nil;
}
}
}
return nil;
}
/**
Assuming the receiver is a radio button, finds other radio buttons in the group (i.e. in the same superview and with the same action) and performs the block for each of them, passing the radio to the block. Invoke this on any of the radios in the group.
@param block A block that takes a radio button and stop boolean reference as parameters and returns void.
@author DJS 2015-01.
*/
- (void)dejal_enumerateRadiosUsingBlock:(void (^)(NSButton *radio, BOOL *stop))block;
{
for (NSButton *radio in self.superview.subviews)
{
// There's no reliable way to determine if a button is actually a radio button, but it's reasonable to assume that no non-radio will have the same action (and having the same action is what makes it a member of the group):
if ([radio isKindOfClass:[NSButton class]] && radio.action == self.action && block)
{
BOOL stop = NO;
block(radio, &stop);
if (stop)
{
return;
}
}
}
}
@end
To use these methods, simply invoke on any of the radios in the group, e.g.
[self.iconNoneRadio dejal_selectRadioWithTag:self.statusIconKind];
self.iconNoneRadio.dejal_radiosEnabled = use;
And:
- (IBAction)chooseIcon:(id)sender;
{
self.statusIconKind = self.iconNoneRadio.dejal_selectedRadioTag;
[self maintainControls];
}
I hope this helps others! And, of course, if I'm missing anything obvious, or you have any suggestions or comments, please let me know.
This look useful? Do check out my other open source projects, too.
(Looking for an iOS or Mac developer? I'm available for contract or full-time work. Learn more about me.)
I just released another open source collection of categories: DejalAppKitExtensionCategories.
DejalAppKitExtensionCategories is a collection of categories to extend Foundation classes with methods specific to OS X. The categories include:
NSDictionary
and NSMutableDictionary
to support NSColor
values.NSObject
base class with an old-style modal did-end perform selector, and modifier key detection.NSUserDefaults
.These categories depend on the previously-published DejalFoundationCategories.
You can get the code and more information from the Dejal Open Source page.
Next up: my UIKit categories.
(Looking for an iOS or Mac developer? I'm available for contract or full-time work. Learn more about me.)
I just released some more open source code: DejalAppKitCategories.
DejalAppKitCategories is a collection of categories for AppKit on OS X, to add useful methods to classes like NSMenu
, NSTableView
, NSTextView
, and others. The categories include:
You can get the code and more information from the Dejal Open Source page.
Stay tuned for more OS X and iOS open source code, coming your way over the next week or so.
(Looking for an iOS or Mac developer? I'm available for contract or full-time work. Learn more about me.)
Today I released two new open source projects: a tiny one, DejalUtilities, and a significantly larger one, DejalFoundationCategories.
DejalFoundationCategories is a collection of Foundation-level categories, to add useful methods to classes like NSArray
, NSDictionary
, NSString
, and others. They work on both OS X and iOS, and include:
NSArray
and NSMutableArray
, including object matching, reversal, sorting, deep copying, adding and removing.NSAttributedString
and NSMutableAttributedString
, including convenience initializers, RTF and font methods.NSDate
, including convenience initializers, handy date component properties and calculators, JSON date support, string formatting, and relative date output.NSDictionary
and NSMutableDictionary
, including object matching, scalar support, deep copying, and more.NSFileManager
, including convenient file attributes, file renaming, and path building.NSObject
base class, including key-value conveniences, “equivalent” comparisons, and performSelector
methods.NSString
and NSMutableString
, including scalar value formatting, contains evaluation, comparisons, substring and range utilities, reformatting, checksum and encoding utilities, internet utilities, file path methods, and appending and replacing methods.NSUserDefaults
, including support for default values, sanitizing values, time intervals, factory settings, and copying preferences.DejalUtilities is a single header file with some useful #define
macros and static functions, also for both OS X and iOS:
DejalClassAvailable()
and DejalClassSelectorAvailable()
macros, to help determine available APIs.DejalIntervalFromMinutes()
, DejalIntervalFromDays()
, DejalMinutesFromInterval()
, DejalMonthsFromInterval()
, and similar macros, to convert seconds to and from other units.DEJAL_FILE_NAME
and DEJAL_COMPILE_DATE_TIME
macros, to help with debug information.DejalWeakSelf
macro to easily make a weak representation of self for use with blocks.You can get the code and more information from the Dejal Open Source page.
(Looking for an iOS or Mac developer? I'm available for contract or full-time work. Learn more about me.)