Objective-Shorthand is a set of categories on Foundation objects that make long things in Objective-C short.
What types of things can Objective-Shorthand help with?
There are many situations in Cocoa where doing a thing that should be simple is actually very involved. For example, checking if a string matches a regular expression is a 3 line process:
NSRegularExpression *regularExpression = [NSRegularExpression regularExpressionWithPattern:regex options:0 error:nil];
NSUInteger numberOfMatches = [regularExpression numberOfMatchesInString:self options:0 range:NSMakeRange(0, self.length)];
BOOL doesMatch = numberOfMatches > 0;
There are certainly lots of options and power in those lines, but 90% of the time, I just want to know if the string matches the regex:
BOOL doesMatch = [string matchesRegex:regex];
This is what Objective-Shorthand does. A method to find the range of the first match for a given regex is also included:
- (NSRange) rangeOfFirstSubstringMatching:(NSString*)regex;
JSON
Using NSJSONSerialization
, you have convert your strings to NSData
before deserializing them to arrays and dictionaries. Objective-Shorthand simplifies all that.
It provides the same interface as JSONKit
, but it works with the built-in Apple JSON serializer behind the scenes. The Ruby community is very good at writing libraries with consistent interfaces, and this is something we need to steal as writers of Objective-C.
To convert from a JSON string to an NSArray
or NSDictionary
:
- (id) objectFromJSONString;
And to convert from an array or dictionary to an NSString
:
- (NSString *)JSONString;
NSComparisonMethods
The OS X SDK has a weird API called NSComparisonMethods. Basically, this API provides a wrapper around compare:
and uses it define the following methods:
- (BOOL)isEqualTo:(id)object;
- (BOOL)isLessThanOrEqualTo:(id)object;
- (BOOL)isLessThan:(id)object;
- (BOOL)isGreaterThanOrEqualTo:(id)object;
- (BOOL)isGreaterThan:(id)object;
- (BOOL)isNotEqualTo:(id)object;
For some reason, this never made it over to iOS, even though it’s tremendously useful. I like these methods because they’re way more semantic than the regular compare:
method. [object isGreaterThan:otherObject]
is way easier to understand than [object compare:otherObject] == NSOrderedDescending
.
If the object in question doesn’t respond to compare:
, an exception will be thrown.
Data Detection Convenience Methods
NSDataDetector
can be a handful sometimes. Objective-Shorthand simplifies complex NSDataDetector
that take a few complex lines of code:
NSDataDetector *dataDetector = [NSDataDetector dataDetectorWithTypes:NSTextCheckingTypeDate error:nil];
NSTextCheckingResult *firstMatch = [dataDetector firstMatchInString:self options:0 range:NSMakeRange(0, self.length)];
return firstMatch.range.location == 0 && firstMatch.range.length == self.length;
and simple to one short method call:
- (BOOL) isDate;
- (BOOL)isEmail
, - (BOOL)isURL
, - (BOOL)isPhoneNumber
, and - (BOOL)isAddress
are available, too.
NSArray Convenience Methods
Pulling out the unique elements of an array involves the ever-goofy [array valueForKeyPath:@"@distinctUnionOfObjects.self"]
. This is wrapped up inside of the following method:
- (NSArray*) uniquedArray;
You never have to remember how to type that string literal again! Autocomplete Rules Everything Around Me.
- (NSArray*)sortedArray
and -reversedArray
are also in Objective-Shorthand.
Functional Collection Operators
Finally, Objective-Shorthand provides categories on NSArray
, NSDictionary
, and NSSet
that provide the normal functional collection operators, like map
, select
, and any
, but with names that are both more semantic and more native to Objective-C. For me, this means I never have to look up what match:
means, ever again.
each
is already defined in Foundation, so it is not included.
- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSUInteger idx, BOOL *stop))block;
Filtering by block with select
(aka filter
) and reject
can be bound:
- (NSArray*) arrayBySelectingObjectsPassingTest:(BOOL (^)(id object))test;
- (NSArray*) arrayByRejectingObjectsPassingTest:(BOOL (^)(id object))test;
map
(aka collect
) and reduce
(aka inject
) are available as well.
- (NSArray*) arrayByTransformingObjectsUsingBlock:(id (^)(id object))block;
- (id) objectByReducingObjectsIntoAccumulator:(id)accumulator usingBlock:(id (^)(id accumulator, id object))block;
sample
and match
are available.
- (id) firstObjectPassingTest:(BOOL (^)(id object))test;
- (id) randomObject;
And finally, some boolean operators:
- (BOOL) allObjectsPassTest:(BOOL (^)(id object))test;
- (BOOL) anyObjectsPassTest:(BOOL (^)(id object))test;
- (BOOL) noObjectsPassTest:(BOOL (^)(id object))test;
All of the above methods with respective changes are also included for NSSet
and NSDictionary
.
Using Objective-Shorthand
Use Cocoapods to get Objective-Shorthand:
pod 'Objective-Shorthand', '~> 1.0'
Find Objective-Shorthand on GitHub at https://github.com/khanlou/Objective-Shorthand/.
If you have questions, comments, or suggestions, please get in touch. You can find me on Twitter at @khanlou and email at soroush@khanlou.com.