November 24 2009
Cocoa Tip: Extend NSNumber
As I mentioned in my last post, categories are such a nice addition to Objective-C. They allow me to wrap up new functionality in a standard class without subclassing it myself. Below, I extend NSNumber with two handy methods for printing out numbers and bytes in a human-readable version, turning 1,000,000 into 1 M and 976.6 KB, respectively.
@implementation NSNumber (Utilities)
- (NSString *)humanReadableBase10 {
if (self == nil) return nil;
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
[formatter setMaximumFractionDigits:1];
NSString *formattedString = nil;
uint64_t size = [self unsignedLongLongValue];
if (size < 1000) {
NSString *formattedNumber = [formatter stringFromNumber:[NSNumber numberWithFloat:size]];
formattedString = [NSString stringWithFormat:@"%@ B", formattedNumber];
}
else if (size < 1000 * 1000) {
NSString *formattedNumber = [formatter stringFromNumber:[NSNumber numberWithFloat:size / 1000.0]];
formattedString = [NSString stringWithFormat:@"%@ KB", formattedNumber];
}
else if (size < 1000 * 1000 * 1000) {
NSString *formattedNumber = [formatter stringFromNumber:[NSNumber numberWithFloat:size / 1000.0 / 1000.0]];
formattedString = [NSString stringWithFormat:@"%@ MB", formattedNumber];
}
else {
NSString *formattedNumber = [formatter stringFromNumber:[NSNumber numberWithFloat:size / 1000.0 / 1000.0 / 1000.0]];
formattedString = [NSString stringWithFormat:@"%@ GB", formattedNumber];
}
[formatter release];
return formattedString;
}
- (NSString *)humanReadableBase2 {
if (self == nil)
return nil;
NSNumberFormatter *formatter = [[NSNumberFormatter alloc] init];
[formatter setNumberStyle:NSNumberFormatterDecimalStyle];
[formatter setMaximumFractionDigits:1];
NSString *formattedString = nil;
uint64_t size = [self unsignedLongLongValue];
if (size < 1024) {
NSString *formattedNumber = [formatter stringFromNumber:[NSNumber numberWithFloat:size]];
formattedString = [NSString stringWithFormat:@"%@ B", formattedNumber];
}
else if (size < 1024 * 1024) {
NSString *formattedNumber = [formatter stringFromNumber:[NSNumber numberWithFloat:size / 1024.0]];
formattedString = [NSString stringWithFormat:@"%@ KB", formattedNumber];
}
else if (size < 1024 * 1024 * 1024) {
NSString *formattedNumber = [formatter stringFromNumber:[NSNumber numberWithFloat:size / 1024.0 / 1024.0]];
formattedString = [NSString stringWithFormat:@"%@ MB", formattedNumber];
}
else {
NSString *formattedNumber = [formatter stringFromNumber:[NSNumber numberWithFloat:size / 1024.0 / 1024.0 / 1024.0]];
formattedString = [NSString stringWithFormat:@"%@ GB", formattedNumber];
}
[formatter release];
return formattedString;
}
@end
UPDATE: I changed the method names to humanReadableBase2 and humanReadableBase10 per Sean’s point.