iPhone managing reusable UIImages and UIViews - iphone

What is the best way to keep my UI constants in seperate class accesible from all controllers?
UIView, UIImage and UIColour all these images and colours create a such mess of allocations and releases in my controllers and most of them are even same. Instead of alloc/relase the same images and views, CAlayers over and over again in different classes, I want to create them once, cache them (or something like that) and easily access when needed.
I want to keep memory and my code clean.

yes , its possible
create a class like gconstants , then store all your string here in h/m files
extern NSString *const APP_TITLE;
#interface UIColor (APP)
+(UIColor *) APP_NAV_COLOR;
#end
in .m file
NSString *const APP_TITLE = #"APP Name";
#implementation UIColor (APP)
+(UIColor *) APP_NAV_COLOR { return [UIColor colorWithRed:00/256.0 green:111/256.0
blue:59/256.0 alpha:1.0]; }
#end
and in any controller declare the header file
self.title = APP_TITLE;

You could use some macro's defined in a header file which you can then include in all the appropriate implementation files, or even in your prefix.pch if you want to make them available to every file in your project.
As an example, imagine a header file called Config.h
For a shared UIColor you could add the following ...
#define SOME_CONSTANT_COLOR [UIColor colorWithRed:0.5f green:0.5f blue:0.5f alpha:0.5f]
And then you can access it the same way as you would use any other macro ...
#import "Config.h" // at the top of you implmentation file, or prefix header
someView.backgroundColor = SOME_CONSTANT_COLOR;
The same also goes for images as well ..
#define SOME_IMAGE [UIImage imageNamed:#"someImage.png"]; // In config.h
myImageView.image = SOME_IMAGE; // In implementation file

Related

Can I reuse colors in Interface Builder?

I've got several yellow buttons created using Inteface Builder. All have the same color. Currently I declare color in each xib. Can I declared it globally and reuse across all xibs?
Not possible in Interface Builder. Do it in code, for example by creating special subclass of the button.
You could use system Color Palette to save the color, but you still need to apply it to all buttons every time you decide to change it. Or you can just use Recently Used Colors in the color chooser, but neither way is enough dynamic.
Yes, you can do this.
At the bottom of the color picker popup in Interface Builder, there's a row of squares you can use to store colors for later use. Drag a color into it from the rectangle where the current color is shown at the top of the color picker to store it, and then just click a stored color later to use it.
I don't believe there is a way to do this entirely in interface builder, unfortunately. However, you can come pretty close with a little bit of code. The best way I've found to be able to change colors throughout the app in one go is to subclass the item that you want to color (UILabel, for instance) to set the color upon initialization:
#interface HuedUILabel : UILabel
#end
#implementation HuedUILabel
- (id)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (self) {
// Initialization code
self.textColor = [AppConfig primaryColor];
}
return self;
}
#end
Then, set the label to have a custom class in IB:
Now, when you want to change the color of all your UILabels, you can do it by changing your one color def AND you don't have to clutter your code with a bunch of appearance assignments.
Most definitely!
Create a singleton object (you can call it OksanaColor, to be cool)...
... or, if you're really lazy, a read-only UIColor property that you can access from your app delegate.
You can also add a category on UIColor, so you can use it same as when you use UIColor. For example in my App I add a new file called ApplicationColors which contains all my app colors.
#interface UIColor (ApplicationColours)
+(UIColor *)savaColor;
#end
Implementation:
#implementation UIColor (ApplicationColours)
+(UIColor *)savaColor
{
return [UIColor colorWithRed:228.0f/255.0f green:86.0f/255.0f blue:86.0f/255.0f alpha:1.0f];
}
#end
Then to use it in my app, I import the ApplicationColours.h and use the same as any other UIColor. i.e:
label.textColor = [UIColor savaColor];
Here's a very simple implementation of a named colors category for UIColor. With this code in your project, UIColor will remember any colors you want to save, and will let you access your own colors or system colors using +colorWithName:
#interface UIColor (namedColors)
+ (UIColor *) colorWithName:(NSString *) name;
+ (void) setColor:(UIColor *) color forName:(NSString *) name;
#end
static NSMutableDictionary *colorStorage;
#implementation UIColor (namedColors)
+ (NSMutableDictionary *) colorStorage
{
if (!colorStorage)
colorStorage = [[NSMutableDictionary alloc] initWithCapacity:10];
return colorStorage;
}
+ (UIColor *) colorWithName:(NSString *) name
{
UIColor *result =[[self colorStorage] valueForKey:name]; // See if we have a color with this name in the colorStorage.
if (result) return result;
SEL selector = NSSelectorFromString(name); // look for a class method whose selector matches the given name, such as "blueColor" or "clearColor".
if ([self respondsToSelector:selector] && (result = [self performSelector:selector]))
if ([result isKindOfClass:[self class]])
return result;
return nil;
}
+ (void) setColor:(UIColor *) color forName:(NSString *) name
{
[[self colorStorage] setValue:color forKey:name];
}
#end

Static UIImage in whole application

I want to have an static UIImage so I could access it from different classes. I've tried this way, but didn't worked:
Made Constans.h file with:
static UIImage *myImage;
And after that I import this header where it's needed. I thought that at this moment myImage was static and any changes made on this object would be visible everywhere. But it looks like every class is working on it's own myImage instance. Is there any way to have such static UIImage?
Edit:
Property in AppDelegate works fine. I have now static UIImage, but still I don't have effect I was expecting.
I have an UIImageView in ViewController. I load an image to my delegate.myImage and after I do:
delegate.myImage = [UIImage imageNamed:#"blah.png"];
myImageView.image = delegate.myImage;
Image is loaded, but after I want to change it in AppDelegate, but when I change myImage this way:
delegate.myImage = [UIImage imageNamed:#"blah2.png"];
nothing change in myImageView. It's like myImageView.image = delegate.myImage copied memory address of myImage so after if I change reference of myImage it's not affecting myImageView.image. I wanted to have an UIImage that after any changes it would also affect myImageView.
Is there other way than having an reference to myImageView in AppDelegate?
Rather than making an explicitly application-wide image, just use [UIImage imageNamed:]. This handles caching of the image for you! Whereever you need to use the image, just access it like so:
[UIImage imageNamed:#"imageName.png"]
Note: this will cause there to be a single copy of the image in memory. You can't unload it -- but newer versions of iOS may unload it behind the scenes upon low memory conditions.
See also the API docs for [UIImage imageNamed:].
Btw, imageNamed is often used for small images that get used multiple times -- e.g. table cell images -- but there's no reason to not use it on large images if you genuinely want a static app-wide image.
The keyword static makes a variable local to the compilation unit where it id defined. This means you can safely have the same symbol defined in multiple .c files; all those declarations will not collide and each file will have its own private symbol.
Put simply, if you really want to define a global variable that is accessed by any part of your program, you do not need the static keyword. In this case, though, the "trick" is declaring the variable in a header file (that you include everywhere the global should be visible) like this:
extern UIImage *myImage;
and then provide a definition for that variable in one single place (.c file) without the static keyword. The extern keyword tells the compiler that the definition for that symbol is not found inside of the current compilation unit (.c file), but in a different one.
Now, as many others have pointed out, you could better do that by means of a singleton, although it is usually recognized that using a singleton to mask a global variable is usually a way to mask a design problem.
That's a C problem (not specifically related to Objective-C or iOS)
The static keyword make the variable sticky inside its compilation unit.
When you #include (or #import in ObjC) a header, that's like if its content were copied & pasted into the file that includes it. As a reminder, ".h" files are not compiled (they are just included in ".m" files that themselves compile)
So that works exactly the same way as if you were typing the same lines of code you have in your .h in any file that #include it.
This explains why in each of your source files that #include "Constants.h" they each see a different instance of the myImage variable.
Instead you should:
Use the Singleton Pattern, that is specifically made for such cases
Or use the static keyword in an implementation file ("Constants.m") to make this variable sticky inside the compilation unit of this "Constants.m" file
I highly recommand to go with the Singleton Pattern for such cases anyway. More info on Singleton Pattern here in the Apple official DevPedia
You can create a #property (nonatomic, retain) UIImage *image; in your app delegate and in every class you want to use the image you can create AppDelegate *delegate=(AppDelegate *)[[UIApplication sharedApplication] delegate]; and then access to the UIImage from the delegate object like this :
[imageView setImage:[delegate image]];
Or you can use a class like this :
header file
#interface Data : NSObject
#property (nonatomic, strong) UIImage *image;
+ (Data *)sharedInstance;
+ (id)allocWithZone:(NSZone*)zone;
- (id)init;
- (id)copyWithZone:(NSZone *)zone;
#end
implementation file
#implementation Data
#synthesize image;
static Data *sharedInstance=nil;
+ (Data *)sharedInstance {
if (sharedInstance == nil) {
sharedInstance = [[super allocWithZone:NULL] init];
}
return sharedInstance;
}
+ (id)allocWithZone:(NSZone*)zone {
return [self sharedInstance];
}
- (id)init
{
self = [super init];
if (self) {
}
return self;
}
- (id)copyWithZone:(NSZone *)zone {
return self;
}
#end
Then, you have to import Data.h in every class you want and then use :
UIImageView *imageView=[[UIImageView alloc] init];
[imageView setImage:[[Data sharedInstance] image]];
This works great for me :)
Use the singleton pattern.
If your code is ARC follow this link http://lukeredpath.co.uk/blog/a-note-on-objective-c-singletons.html
In iPhone the AppDelegate class Acts a Static Class. so you can do the same thing which you have done in Constant.h in the YourAppDelegate Class. But dont use Static Keyword.
I am not very Sure but thinks it will work. :)
You can use UIImage category as example to get this picture.
In your .h file just add your static method.
#import <UIKit/UIKit.h>
#interface UIImage (StaticImage)
+(UIImage *)staticImage;
#end
And in your .m file do following steps:
#import "UIImage+StaticImage.h"
//This is your static image
static UIImage *myStaticImage;
#implementation UIImage (StaticImage)
+(void)initialize{
//Important to add this condition, because this method will be called for every
//child class of UIImage class
if (self == [UIImage class]){
myStaticImage = [[UIImage alloc] init];
}
}
+(UIImage *)staticImage{
//Just return your existing static image
return myStaticImage;
}
#end

iPhone: Constants for a UI element's coordinate and size?

If I am making the user interface programmatically, what is the best way to store constants for a UI element's coordinate and size? #define, or double const? Should I be putting this in the .h, .m, or a separate file?
This is how I do it:
Constants that need to be available to the entire project are in "Project-Prefix.pch" as #define SOMECONST SOMEVAL.
Constants that are only needed within the scope of a class go at the top of the #implementation (.m) file as whatever const whatever whatevr.
For example, wherever I use a UITableView in a view controller, I have this just below the #implementation line:
static NSString *kCustomCellID = #"com.cell.tableview.someviewcontrollername.iphone.universaltemplate.mycompany";
To be used in:
UITableViewCell *cell = (UITableViewCell *)[tableView dequeueReusableCellWithIdentifier:kCustomCellID];
Then, in Universal-Prefix.pch, I have LOCATIONS_URL which is needed in lots of places throughout the project:
#define LOCATIONS_URL [NSString stringWithFormat:#"%#/get_locations.php?uid=%#&device=%#", MY_BASE_URL, CLIENT_APP_UID, DEVICE_NAME]
I personally use #define for sizes etc, just under the #implementation line, writing static CGFloat xx etc is too long and unnecessary in my opinion.

how to access cache from other views

I have set up a sharedCache using ASIHttprequest and it is created from the xml I parse in my subview. I was woundering if I can then access that sharedCache from my mainview to do a few things things that will speed my tables up?
any idea, suggestions, thoughts of examples would be greatly appreciated.
There's already a sharedCache provided by ASIDownloadCache. It's visible anywhere in your application (assuming you #import "ASIDownloadCache.h"), so you should be able to call [ASIDownloadCache sharedCache] and use it.
EDIT: To use several caches is not too tricky. Create a separate class which is included by both your main view and your subview. In there, define a method to return one or more ASIDownloadCache objects, and provide an implementation, similar to this:
DownloadCaches.h
#import "ASIDownloadCache.h"
#interface DownloadCaches : NSObject
+ (ASIDownloadCache *)imageCache;
#end
DownloadCaches.m
#import "DownloadCaches.h"
#implementation DownloadCaches
static ASIDownloadCache *imageCache = nil;
+ (ASIDownloadCache *)imageCache
{
if(imageCache == nil)
{
imageCache = [[ASIDownloadCache alloc] init];
// set imageCache-specific options here
}
return imageCache;
}
#end
You only ever need to call [DownloadCaches imageCache] and it will be initialised if not already, and then returned to you.

How do I set a custom font for the whole application?

Is there any way to How to Apply global font [new custom font] to whole application in iphone objective-c.
I know that we can use below method to set font for each label
[self.titleLabel setFont:[UIFont fontWithName:#"FONOT_NAME" size:FONT_SIZE]];
But I want to change for whole application.
Please help me if anyone know.
Apparently to change ALL UILabels altogether you will need to setup a category on UILabel and change the default font. So here's a solution for you:
Create a file CustomFontLabel.h
#interface UILabel(changeFont)
- (void)awakeFromNib;
-(id)initWithFrame:(CGRect)frame;
#end
Create a file CustomFontLabel.m
#implementation UILabel(changeFont)
- (void)awakeFromNib
{
[super awakeFromNib];
[self setFont:[UIFont fontWithName:#"Zapfino" size:12.0]];
}
-(id)initWithFrame:(CGRect)frame
{
id result = [super initWithFrame:frame];
if (result) {
[self setFont:[UIFont fontWithName:#"Zapfino" size:12.0]];
}
return result;
}
#end
Now ... in any view controller you want these custom font labels, just include at the top:
#import "CustomFontLabel.h"
That's all - good luck
Ican's solution with category might be prefered just to save the day. But avoid using category to override existing methods as apple explains:
Avoid Category Method Name Clashes
... If the name of a method declared in a category is the same as a method in the original class, or a method in another category on the same class (or even a superclass), the behavior is undefined as to which method implementation is used at runtime. ...
Note also that overriding -(id) init; would be safer than overriding -(id)initWithFrame:(CGRect)frame. You would not face with the problem of not receiving touch events when clicking on a label on UIButtons.
Is this what you mean?
#interface GlobalMethods
+(UIFont *)appFont;
#end
#implementation GlobalMethods
+(UIFont *)appFont{
return [UIFont fontWithName:#"someFontName" size:someFontSize];
}
#end
...
[self.titleLabel setFont:[GlobalMethods appFont]];
In case you want to do it somehow automatically (without using setFont on each control), I don't believe it's possible.
If you can limit your application – or this particular feature – to iOS 5, there’s a new API coming that lets you skin the default UI very conveniently. I can’t give you details, since they are still under NDA at the time I am writing this. Take a look at iOS 5 beta SDK to find out more.
CustomLabel.h
#import <UIKit/UIKit.h>
#interface VVLabel : UILabel
#end
CustomLabel.m
#import "CustomLabel.h"
#define FontDefaultName #"YourFontName"
#implementation VVLabel
- (instancetype)initWithCoder:(NSCoder *)aDecoder {
self = [super initWithCoder: aDecoder];
if (self) {
// Initialization code
// Static font size
self.font = [UIFont fontWithName:FontDefaultName size:17];
// If you want dynamic font size (Get font size from storyboard / From XIB then put below line)
self.font = [UIFont fontWithName:FontDefaultName size:self.font.pointSize];
}
return self;
}