Archive for July, 2012

isNotEmpty a Short Objective-C Code Snippet

Sunday, July 29th, 2012

Today Brent Simmons improved the developer pool of reusable code by posting his code for testing if the value of an object is empty. Most programmers start down this path with NSString where for most purposes an empty string is the same as nil. From there it grows to include NSNull which JSON parser will commonly return, as well as other common objects found in collections such as NSNumber and NSDate and the collections themselves NSDictionary and NSArray.

If you take a look at his code you will notice it’s a function (same as Wil Shipley’s). Because I write almost exclusively Objective-C a function call in my code makes me pause and think. I avoid this by using categories and get to call methods instead of functions. This also avoids the issue of having to write an optimized version of the function to remember to use on NSStrings. With a category you can optimize each individual call for the specific object. So in the hope of improving that shared code pool below is my implementation. Overwhelmingly (97.63% of the time so far) I want to do something with an object when it’s not empty, so my method is reversed. Also isNotEmpty sent to a nil object will result in the correct NO value being returned.

@interface NSString (NSStringExtensions)
- (BOOL)isNotEmpty;
@end

@interface NSNull (NSNullExtensions)
- (BOOL)isNotEmpty;
@end

@interface NSNumber (NSNumberExtensions)
- (BOOL)isNotEmpty;
@end

@interface NSDate (NSDateExtensions)
- (BOOL)isNotEmpty;
@end

@interface NSArray (NSArrayExtensions)
- (BOOL)isNotEmpty;
@end

@interface NSDictionary (NSDictionaryExtensions)
- (BOOL)isNotEmpty;
@end


@implementation NSString (NSStringExtensions)
- (BOOL)isNotEmpty {
	if ([self length] > 0)
		return YES;
	return NO;
}
@end

@implementation NSNull (NSNullExtensions)
- (BOOL)isNotEmpty {
	return NO;
}
@end

@implementation NSNumber (NSNumberExtensions)
- (BOOL)isNotEmpty {
	if ([self integerValue] == 0)
		return NO;
	return YES;
}
@end

@implementation NSDate (NSDateExtensions)
- (BOOL)isNotEmpty {
	if (self != nil)
		return YES;
	return NO;
}
@end

@implementation NSArray (NSArrayExtensions)
- (BOOL)isNotEmpty {
	if ([self count])
		return YES;
	return NO;
}
@end

@implementation NSDictionary (NSDictionaryExtensions)
- (BOOL)isNotEmpty {
	if ([self count])
		return YES;
	return NO;
}
@end

I wrote these categories in 2003 and haven’t thought about them since then. I have 674 total calls to these functions in my code (how I know the exact percentage on how often I use it). Since I recently discovered the easy to use BNRTimeBlock for testing performance I ran the three implementation 10 million times and came up with the following averages after 10 runs:

Time for == King Kong
Conor's isNotEmpty:       0.165795
Brent's RSStringIsEmpty:  0.182188
Wil's isEmpty:            0.860662

Time for == (null)
Conor's isNotEmpty:       0.045048
Brent's RSStringIsEmpty:  0.039325
Wil's isEmpty:            0.041882

Time for == @""
Conor's isNotEmpty:       0.167456
Brent's RSStringIsEmpty:  0.186889
Wil's isEmpty:            0.329623

Average:                  0.224318

This shows that at .000000022 seconds per call you should be using these easy to read and maintain functions and/or methods all over your Objective-C code. Brent’s longer RSIsEmpty performs similar to Wil’s function as it includes the necessary call to respondsToSelector:. At these speeds I think the RSStringIsEmpty optimization is unnecessary except in the heaviest of loops.

I do believe my version should be renamed isSet or isFull to avoid using “not” in the method name; but although one learns a lot in 10 years, I also have been using isNotEmpty for 10 years.