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
Related
I would like to inherit from a framework class that has a factory method. How can I make the factory method return an object of my inherited class type? I found this useful article which describe a similar situation but in their case you have control over the superclass. How could I write, say, a subclass of UIImage that imageNamed: would return an object of my subclass type?
I would like to inherit from a framework class that has a factory method. How can I make the factory method return an object of my inherited class type?
This is all you should have to do:
#interface MONImage : UIImage
#end
#implementation MONImage
#end
Then:
MONImage * image = [MONImage imageNamed:name];
How could I write, say, a subclass of UIImage that imageNamed: would return an object of my subclass type?
+[UIImage imageNamed:]'s implementation wrote subclassers out of this approach. Consequently, you would need to implement this method yourself.
Here's how one should declare a factory method:
+ (instancetype)imageNamed:(NSString *)pName;
and how one should implement it:
+ (instancetype)imageNamed:(NSString *)pName
{
MONImage * image = [[self alloc] initWithThisDesignatedInitializer:pName];
^^^^ NOTE: self, not a concrete class
...set up image...
return image;
}
but they did not do it that way -- +[UIImage imageNamed:] wrote subclasses out and returns a UIImage when you write MONImage * img = [MONImage imageNamed:pName];. Sometimes that is done for a good reason. Some methods should have 'final' semantics. This often appears when your method may return multiple types, as in a class cluster. The language does not express 'final' methods -- but such a method should at least be documented.
So to come around to this UIImage case:
#interface MONImage : UIImage
+ (instancetype)imageNamed:(NSString *)pName;
#end
#implementation MONImage
+ (instancetype)imageNamed:(NSString *)pName
{
UIImage * source = [UIImage imageNamed:pName];
CGImageRef cgImage = source.CGImage;
if (cgImage)
return [[self alloc] initWithCGImage:cgImage];
// try it another way
return nil;
}
#end
Note that UIImages and CGImages are immutable. This should not result result in a deep copy of the image data.
For your example:
Subclass UIImage to, say, MyImage
Implement the imageNamed: method to do anything specific that you need to be done.
Call that method on that class: MyImage *newImage = [MyImage imageNamed:imageName];
The approach that solved my problem was to use a category instead of inheritance (credits go to Jonathan Cichon in the comments of my question). I used Associative References to declare and store additional data in the category implementation as discussed a lot here in SO. I would like to drive the attention to the NSObject category implementation proposed by Jonathan that makes really easy and elegant to add associative references to any object.
I am stuck on what is supposed to be a very simple thing to do: have a Core Data Entity store / display (through bindings) an image assigned as a transformable attribute.
I've read many related posts on the Stack (e.g., see here and here), but am still having trouble with it, after having developed sample code and researched other articles (e.g., see here as well as here). This is related to my earlier question, which I still have not resolved.
I created a simple doc-based Core Data App to demonstrate the problem. The Core Data managed object is called "TheEntity" and the attribute "theImageAtt." The entity as defined in Core Data is shown below (ImageValueTransformer is the NSValueTransformer):
I let XCode generate the NSManagedObject subclass header and implementation files (I left out the code for the "name" attribute to make it simpler):
// TheEntity.h
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
#import "ImageValueTransformer.h"
#interface TheEntity : NSManagedObject
#property (nonatomic, retain) NSImage * theImageAtt;
#end
-----------------------
// TheEntity.m
#import "TheEntity.h"
#implementation TheEntity
#dynamic theImageAtt;
#end
Below are the header and implementation files for my "ImageValueTransformer." Lots of examples of this on the Stack and elsewhere (the tiff rep is arbitrary).
// ImageValueTransformer.h
#import <Foundation/Foundation.h>
#interface ImageValueTransformer : NSValueTransformer
#end
-------------------------------
// ImageValueTransformer.m
#import "ImageValueTransformer.h"
#implementation ImageValueTransformer
+ (BOOL)allowsReverseTransformation {return YES;}
+ (Class)transformedValueClass {
return [NSData class]; // have also tried: return [NSImage class];
}
- (id)transformedValue:(id)value {
NSData *data = [value TIFFRepresentation];
return data;
}
- (id)reverseTransformedValue:(id)value {
NSImage *imageRep = [[NSImage alloc] initWithData:value];
return imageRep;
}
#end
The Value Transformer can be initialized / registered by allocating an instance of it in MyDocument.m, but in the end, it doesn't matter that much as long as the transformer header is imported into the theEntity Header (see above). I have experimented with this and it does not remove the error I get below. For reference, there is earlier discussion on whether or not the value transformer needs to be registered (see the comments by CornPuff and Brian Webster).
Back to the problem at hand, a good code example from Apple is here which shows an alternative initialization of the value transformer, I tried that setup too.
Putting this into action, I have a method to load a test image and assign it to the transformable attribute in MyDocument.m (from a selected Entity instance in an NSTable):
- (IBAction)addImg:(id)sender {
NSImage *theImg = [[NSImage alloc] initWithContentsOfFile:#"/Desktop/testImage.jpg"];
//[theImageView setImage:theImg]; // as a test, this displays ok
// "theEntities" below are defined as an IBOutlet to my Array Controller:
[theEntities setValue:theImg forKeyPath:#"selection.theImageAtt"];
NSLog(#"after setting the image ..."); // this never logs
}
Zeroing-in on where the code breaks, the line below:
[theEntities setValue:theImg forKeyPath:#"selection.theImageAtt"];
gives the error:
Cannot create BOOL from object <4d4d002a 0003717e 8989898a 8a8a8b8b 8b8b8b8b
8a8a8a89 89898888 88878787 8a8a8a89 89898888 88888888 88888889 89898a8a
8a8a8a8a 8b8b8b88 88888787 87898989 8a8a8a89 89898a8a 8a8c8c8c 8b8b8b8a
8a8a8888 .... and so on for the size of the Image array ...
If I comment out the said line above then my NSTable populates just fine (so the bindings and array controller seem ok), but of course with no image in the NSImageView.
As a check, the conversion code used in the Image Transformer works as expected (this is tested separately from the value transformer):
// Image to Data Conversion:
NSImage *imageIn = [[NSImage alloc] initWithContentsOfFile:#"testImage.jpg"];
NSData *imgData = [imageIn TIFFRepresentation];
NSImage *imageOut = [[NSImage alloc] initWithData:imgData];
[theImageDisplay setImage:imageOut];
What am I missing on this?
I found that the error reported above, namely,
Cannot create BOOL from object ...
does not occur when using an Image Well or Image Cell (subclasses of NSImageView) rather than the Custom View that I was trying to write to earlier.
So for now I'm using the default value transformer rather than a custom value transformer. This is a workable solution, but academically speaking, it would be nice to know why the default Custom View led to errors when binding to a Core Data attribute (defined as transformable in the Core Date Model).
Digging into this a little further, the Image Well inherits from NSImageView, so at least one difference is that they are distinct with regard to the "editable" property (Image Wells are editable which plays well with Drag-n-Drop). So in an attempt to reconcile these two, I set my Custom View to editable, thinking that this might resolve the problem:
theImageView = [[NSImageView alloc] init];
[theImageView setEditable:YES];
But it must be something else, this does not resolve the error above. For now at least, I have a workable solution. Should others encounter this, I hope these notes are helpful!
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.
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
I've been trying to figure out how to have a UIImageView with a next and previous button which when clicked will go to the next or previous image in the array. So far, here's what I have.
In my .h file I have declared:
IBOutlet UIImageView *imageView;
NSArray *imageArray;
And I also added:
-(IBAction) next;
In the .m file I have:
-(void) viewDidLoad;
{
imageArray = [[NSArray arrayWithObjects:
[UIImage imageNamed:#"1.png"],
[UIImage imageNamed:#"2.png"],
nil] retain];
}
Now here is where I'm struggling. I have the IBAction defined as follows in my .m:
-(IBAction)next
{
if (currentImage + 1 == [imageArray count])
{
currentImage = 0;
}
UIImage *img = [imageArray objectAtIndex:currentImage];
[imageView setImage:img];
currentImage++;
}
My problem is that I do not know where to define the currentImage index integer or how to define it. Is it in the header? The implementation? And how exactly do I declare it?
To be honest I'm not even 100% sure the code I currently have is right, although I think if I can define the index, it will work.
Any advice?
This is how I would do it. (I've changed the name of a few instance variables: currentImage sounds like it could be a pointer to an image (UIImage *) rather than just an integer value; adding Index to the end makes that more clear. It may be obvious now that it's an integer, but when you revisit this code (or other code you write) in a month, it may be less obvious; or maybe that's just me)...
MDSlideshowController.h:
#import <UIKit/UIKit.h>
#class MDBilboBaggins;
#interface MDSlideshowController : NSObject {
IBOutlet UIImageView *imageView;
NSArray *imageArray;
NSUInteger currentImageIndex;
BOOL someOtherVariable;
MDBilboBaggins *bilboBaggins;
// keep adding more instance variables as needed
}
- (IBAction)previous:(id)sender;
- (IBAction)next:(id)sender;
#end
MDSlideshowController.m:
#import "MDSlideshowController.h"
#import "MDBilboBaggins.h"
// you could perhaps define currentImageIndex here, but see notes below:
// NSUInteger currentImageIndex = 0;
#implementation MDSlideshowController
// `currentImageIndex` is automatically initialized to 0 during init
// `someOtherVariable` is automatically initialized to 0 (NO) during init
-(void) viewDidLoad
{
imageArray = [[NSArray arrayWithObjects:
[UIImage imageNamed:#"1.png"],
[UIImage imageNamed:#"2.png"],
nil] retain];
[imageView setImage:[imageArray
objectAtIndex:currentImageIndex]];
}
- (IBAction)previous:(id)sender {
if (currentImageIndex == 0) {
currentImageIndex = [imageArray count] - 1;
} else {
currentImageIndex--;
}
[imageView setImage:[imageArray objectAtIndex:currentImageIndex]];
}
- (IBAction)next:(id)sender {
if (currentImageIndex + 1 >= [imageArray count]) {
currentImageIndex = 0;
} else {
currentImageIndex++;
}
[imageView setImage:[imageArray objectAtIndex:currentImageIndex]];
}
#end
Basically, you put instance variables right underneath the ones you've already defined. They can be of almost any type. You can use the types Cocoa Touch knows about, or classes you make yourself. In this example, I said that there was a special class named MDBilboBaggins by using the #class MDBilboBaggins statement. Then, I add the #import "MDBilboBaggins.h" part in the .m file: this can help speed up compile times.
As I mentioned in the comment, you could perhaps define the currentImageIndex variable inside the .m file, however, it would be a static variable that is common to, and shared, by all instances of the class. This can be useful in some situations, but create issues in others. For example, imagine we have 2 slideshow controllers, each with different images created and showing slides in 2 different windows. If they were modifying a shared currentImageIndex variable, they'd mess each other up if you would switch between them and start clicking Previous and Next indiscriminately. That's why in this case it might make more sense to just make it an instance variable by defining it other your other instance variables in the .h file.
[EDIT] Regarding the :(id)sender parameter: in this example, it wasn't used at all, I generally do it out of habit, since in some circumstances, it can save a lot of code, and simplify things dramatically. For example, say you had 9 different buttons and you wanted each button to load a specific image (or perform a specific operation). Now, you could define 9 separate methods like - (IBAction)button1Clicked;, or you could do it the easy way and just define a single - (IBAction)loadImage:(id)sender method. In your nib file, you would give each button a different tag (an NSInteger value), like 1 − 9. Then in your single method you could do this:
- (IBAction)loadImage:(id)sender {
NSInteger buttonTag = [(NSButton *)sender tag];
[imageView setImage:[UIImage imageNamed:
[NSString stringWithFormat:#"image%ld.png",buttonTag]]];
}
In this case, sender is the object that sends the message, which would be the button that was clicked on. Though admittedly a contrived example, by providing that one additional parameter, I probably saved 100 lines of needless code and complexity of having 9 separate methods.
[EDIT #2] Replaced the one pseudo-coded (written in Safari) next: method with actual code from one of my apps that I know works.
Hope this helps...
you need to declare the currentindex in the header like so:
NSInteger currentImage;
This way the value is saved throughout the views lifetime