7
\$\begingroup\$

I have a class that I call "Icons"

Icons.h

#import <Foundation/Foundation.h>

@interface Icons : NSObject

+ (UIImage *) someIcon;
+ (UIImage *) someOtherIcon;

+ (NSString *)imageToNSString:(UIImage *)image;
+ (UIImage *)stringToUIImage:(NSString *)string;

@end

Icons.m

#import "Icons.h"

@implementation Icons

+ (UIImage *) someIcon {
    return [self stringToUIImage:[self someIconStr]];
}
+ (UIImage *) menuLines {
    return [self stringToUIImage:[self someOtherIconStr]];
}

+ (NSString *)imageToNSString:(UIImage *)image {
    NSData *data = UIImagePNGRepresentation(image);
    return [data base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed];
}

+ (UIImage *)stringToUIImage:(NSString *)string {
    NSData *data = [[NSData alloc]initWithBase64EncodedString:string options:NSDataBase64DecodingIgnoreUnknownCharacters];
    return [UIImage imageWithData:data];
}

+ (NSString *) someIconStr {
    return @"iVBORw0KGgoAAAANSUhEUgAAABYAAAAoCAYAAAD6xArmAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAHGlET1QAAAACAAAAAAAAABQAAAAoAAAAFAAAABQAAAB5EsHiAAAAAEVJREFUSA1iYKAimDhxYjwIU9FIBgaQgZMmTfoPwlOmTJGniuHIhlLNxaOGwiNqNEypkwlGk9RokoIUfaM5ijo5Clh9AAAAAP//ksWFvgAAAEFJREFUY5g4cWL8pEmT/oMwiM1ATTBqONbQHA2W0WDBGgJYBUdTy2iwYA0BrILDI7VMmTJFHqv3yBUEBQsIg/QDAJNpcv6v+k1ZAAAAAElFTkSuQmCC";
}

+ (NSString *) someOtherIconStr {
    return @"iVBORw0KGgoAAAANSUhEUgAAADIAAAAKCAYAAAD2Fg1xAAAACXBIWXMAABYlAAAWJQFJUiTwAAAAHGlET1QAAAACAAAAAAAAAAUAAAAoAAAABQAAAAUAAACZxAe6RgAAAGVJREFUOBFiYACCmTNn8k+ePLl+0qRJ74H4PxS/B4mB5EkFA2Ye0MHnkTwA8wiYBsmR6pEBMQ8U6rg8ARMHqSHWMwNmHtCxyMkJJTZgHgGpIdYjA2YekmNxeQIsToxHQHljoMwDAAAA//+psxowAAAAWUlEQVRjmDRp0n9iMAMRYObMmfzEmAVSQ4RxDCSZBzT0PRGWvyfGYpCaATNv8uTJ9YQ8AlJDrEcG1Dyg5edxeQYkR6wnYOoG1DxoSCIns/cgMZjjSKXpbR4A1NvIaZrhxd8AAAAASUVORK5CYII=";
}

This way, whenever I need to add an icon to a button or whatever, it's

UIButton * btn;
[btn setImage:[Icons someIcon] forControlState:UIControlStateNormal];

It doesn't seem like a big fix, but here's the main reasons I do it.

  1. Easy To Use Same Icon Library Across Projects
  2. No misspelled image errors
  3. No need to create image file keys
  4. Changing an icon quickly updates all iterations across project

Questions

  1. Anyone else using something similar to this?
  2. Should I store the image strings statically as opposed to returning them via method as is now?
  3. Any other thoughts?
\$\endgroup\$
5
\$\begingroup\$

I do something similar, except rather than creating my own class, I create a UIImage class category.

File names are called UIImage+Icon.h and UIImage+Icon.m.

In the .h, we have this:

@import UIKit.UIImage;

@interface UIImage (Icon)

+ (UIImage*)someIcon;
+ (UIImage*)someOtherIcon;

@end

And then put your code in the .m as normal.

Be sure to note @import UIKit.UIImage; versus the #import. You don't need to import the entire UIKit. @import is new in Xcode 5 and vastly speeds up compile time as it only imports the required modules.

Anyway, the advantage to this versus what you're doing is that we call our methods as such:

[UIImage someIcon];

It's clear as day that we're definitely returning a UIImage object, because we're calling a UIImage class method.

EDIT: Having just noticed that your class also includes a method which returns NSString, I still recommend the class category. In this case, the imageToNSString method would look like this:

- (NSString*)toEncodedString;

The method doesn't take an argument because it is an instance method. Because this is a UIImage class category, you can refer to self, which gives you the UIImage instance on which this method was called.


I personally like the UIImage class category, but another option that is still potentially better than what you're doing would be to create C-style functions.

So you'll have a .h file that would include this function declaration:

UIImage * imageFromString(NSString *str);

As well as a list of NSString * const objects that you send as arguments. Then your .m, you've just got the logic for returning an image from a string.


The main point here is that there are two options here that don't involve a class called Icon. The problem is, if there's a class called Icon, I kind of expect to be working with Icon objects in some way. And I might even try to instantiate an Icon object, which makes no sense...

Ultimately though, if you're NOT going to create a UIImage class category OR use C-style functions and still work with the Icon class, since you only have class methods and your class certainly shouldn't be instantiated, I highly recommend adding this to your .h file:

+ (id)alloc __attribute__((unavailable("Icon class can not be instantiated")));
- (id)init __attribute__((unavailable("Icon class can not be instantiated")));

This will throw red errors and prevent compilation if anyone tries to instantiate the Icon class. This is the worst option of the three I purposed in this situation, but it can be acceptable in some cases perhaps.

\$\endgroup\$
3
  • \$\begingroup\$ I like the alloc blockers, I'll add those in. I originally had it as a UIImage category, but I prefer it as an Icons class only for my own mental organization. What is the benefit of using a function over a method? \$\endgroup\$
    – Logan
    Mar 19 '14 at 22:18
  • \$\begingroup\$ Technically, the function performs slightly better, but you'd never notice it. Even if you're trying to measure the difference, it's hard to detect. The main advantage is readability though. To me, an Icon class means there are Icon objects--there's a method out there SOMEWHERE that will return an Icon object type. If we instead use functions, we're making it more clear that these are simply helper methods for instantiating existing object types. \$\endgroup\$
    – nhgrif
    Mar 19 '14 at 22:26
  • \$\begingroup\$ Consider Apple's own code. There's not a single Foundation class that can't be instantiated. When there's a method that, for whatever reason, Apple doesn't want to include within the relevant class, they provide a function. For example: developer.apple.com/library/ios/documentation/uikit/reference/… \$\endgroup\$
    – nhgrif
    Mar 19 '14 at 22:28

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.