I'm creating an UIImage like this:
UIImage *img = UIGraphicsGetImageFromCurrentImageContext();
Am I responsible for releasing this?
No.
Return Value
An autoreleased image
object containing the contents of the
current bitmap graphics context.
(doc link)
Read the documentation here. As it's written there, it returns an autoreleased object. You don't have to release it. If you want to keep it, you need to retain it somehow.
Related
I want to display some images, when image is not available I want to show a default one.
When using the analyze functionality I get warnings about a potential leak.
I do under stand that when using imageNamed there is no memory allocated, what would be a nice workaround ?
See below a part of my code
if (!isMyFileThere){
image = [UIImage imageNamed:#"default.png"];
}
else{
image = [[UIImage alloc] initWithContentsOfFile:pngFilePath];
}
This is autoreleased
image = [UIImage imageNamed:#"default.png"];
This is not
image = [[UIImage alloc] initWithContentsOfFile:pngFilePath];
You need to do this :
image = [[[UIImage alloc] initWithContentsOfFile:pngFilePath] autorelease];
The rule is if your method name begins with alloc, new, copy or muteableCopy you own it and need to release it yourself, either with release or with autorelease. Anything else isn't yours so you mustn't release it.
If you call retain on an object, you must release (or autorelease) it the same number of times :)
image = [[UIImage alloc] initWithContentsOfFile:pngFilePath]; You have done a alloc and you have to now release it, which is a potential leak if you don't. The other statement is autoreleased object.
If you want to object to stay until you release it manually you should use retain, autorelease adds the object to the current NSAutorelease pool which gets drained at the end of each run loop iteration. if you attempt to use a freed object your program will crash.
in iOS 5.0 if you enable ARC you won't need to use "retain", "autorelease" or "release" anymore. those are added by the compiler automatically.
I'm wondering under which circumstances this code breaks in the second assert. In other words, when can -[UIImage CGImage] return nil? The documentation isn't very telling here.
- (void)setImage:(UIImage *)anImage {
assert(anImage);
CGImageRef cgimage = anImage.CGImage;
assert(cgimage);
}
I'm pretty sure, the UIImage is correct since it's fetched from the app bundle. So far I haven't been able to reproduce the case but I do see some user crash reports.
One more possibility that I've come across in the docs:
If the UIImage object was initialized using a CIImage object, the value of the property is NULL.
Another possibility is that you have multiple threads accessing the same UIImage object at the same time; this was happening in my code with the same symptom.
That might explain your sporadic crash reports, too, since the access patterns would depend on timing that changes from run to run.
To the best of my knowledge, if the first assert passes(showing that anImage is not nil) it means that it could not load the image. Check to make sure that the image is being copied into your bundle.
A case where anImage would be non-nil but cgimage would be nil could be contrived as follows:
UIImage* myImage = [[UIImage alloc] initWithCGImage:nil];
As previous answers have indicated there are other ways one could find themselves in such a scenario.
I have a reasonably complex Core Data app for the the iPhone. For the most part, it's working well, but I'm running into a sporadic problem that manifests itself within Core Data.
I'm fetching data from a remote service, said service returns data. I parse the data and modify various managed objects. Then I save the managed object context and I get an error. In the course of printing the error I get the following message:
*** -[UIImage length]: unrecognized selector sent to instance 0x8cd7aa0
I can isolate the problem down to a single setter in my one of my managed objects. I save the managed object context before using the setting and I save the managed object context right after. Failure happens right after.
This is all being done in the main thread. I have more than one managed object context, but only one persistent store.
Any pointers for debugging this sort of Core Data problem are appreciated.
This particular problem was caused by a method with the word "get" in it that corresponded to a field name in the managed object. It, in turn, masked the real problem which is database related.
I had the same problem, so I crafted a workaround. Subclass the NSManagedObject and manually transform the UIImage by overriding the accessor methods for the image property.
In the setter method, transform the UIImage object into an instance of NSData, and then set the managed object's image property.
In the getter method, transform image property's data, and return an instance of UIImage.
Let's get to work:
In the data model, when you click the attribute, "image", delete the Value Transformer Name's text. It defaults to NSKeyedUnarchiveFromData, which is what you now want.
Next, subclass the entity by clicking on it in the data model, click New File. When you have the entity selected, you should see a new class in Cocoa Touch Classes titled "Managed Object Class." Click Next, leave the file's location as is by clicking Next again, and then put a checkmark next to all the entities you want to subclass.
In the implementation file of your subclassed NSManagedObject, override the image property's accessor methods by including the following two:
- (void)setImage:(UIImage *)image {
[self willChangeValueForKey:#"image"];
NSData *data = UIImagePNGRepresentation(image);
[self setPrimitiveValue:data forKey:#"image"];
[self didChangeValueForKey:#"image"];
}
- (UIImage *)image {
[self willAccessValueForKey:#"image"];
UIImage *image = [UIImage imageWithData:[self primitiveValueForKey:#"image"]];
[self didAccessValueForKey:#"image"];
return image;
}
Then, whenever you set the image, use:
object.image = [UIImage imageNamed:#"icon.png"];
rather than:
[object setValue:[UIImage imageNamed:#"icon.png"] forKey:#"image"];
Whenever you get the image, use:
UIImage *myImage = object.image;
rather than:
UIImage *myImage = [object valueForKey:#"image"];
Does UIImage ever removes images from its cache? Can I keep a pointer to an image I got from imageNamed: and use it as long as I like or must I always call imageNamed:?
The UIImage object that is returned from imageNamed: is treated like all other objects as far a memory management goes. If you want to keep the reference to the object between method calls, you should retain it and release it when you are done to decrement the reference count.
UIImage * cachedImage;
-(void) getTheImage {
UIImage * cachedImage = [[UImage imageNamed:#"MyImage.png"] retain];
//Do something with the image...
}
//In some other method or dealloc
[cachedImage release];
Also, note that the UIImage class reference says:
In low-memory situations, image data
may be purged from a UIImage object to
free up memory on the system. This
purging behavior affects only the
image data stored internally by the
UIImage object and not the object
itself. When you attempt to draw an
image whose data has been purged, the
image object automatically reloads the
data from its original file. This
extra load step, however, may incur a
small performance penalty.
UIImage caches the data itself. You must not hold a pointer and just pass that around. That can be unsafe since when there is a memory warning and there was no strong ref to that object then UIImage will purge cached data. Call [UIImage imageNamed:] every time. It is fast and returns the ref to the image from memory. If the image is no longer in memory it will reload it and pass that ref
I am wondering what the most efficient way is to make a CALayer with an image in it.
I know you can load a UIImage and then call [image CGImage] but is this the best way of going about it? As far as I can tell from Apple's documentation this is the only way you can do it.
Try this:
layer.contents = (__bridge id)[ uiimage CGImage ] ;
HTH
Well, a CGImage isn't a CALayer, so you are obviously leaving some steps out there, but I assume you know what you're talking about, as far as drawing to a CALayer or whatnot.
If your question is about creating CGImages without using a UIImage, you can try looking into the following functions:
CGImageCreateWithJPEGDataProvider
CGImageCreateWithPNGDataProvider
If you happen to know beforehand what sort of image it is, just use the appropriate method. Otherwise, you'd need to look at the file signature to see if it contains PNG or JFIF. Of course, this requires you implement a CGDataProvider.
I assume this is exactly what the UIImage class is already doing. If you want to squeeze out every bit of efficiency from that, you can use one of the following methods in the UIImage class:
+ (UIImage *)imageWithContentsOfFile:(NSString *)path
+ (UIImage *)imageWithData:(NSData *)data
The only difference between these methods and
+ (UIImage *)imageNamed:(NSString *)name
is that imageNamed: caches the image. If you use one of the first methods, it does not.