iPhone App crashes after switching, possibly due to UIImage imageNamed - iphone

My app moves 10 UIImageViews randomly around the screen, and once an UIImageView hits the corner, it changes its image. The problem is: after switching between apps and going back to mine, the app crashes.
The console gives me this message:
"App" exited abnormally with signal 10: Bus error
The crash log states this:
Exception Type: EXC_BAD_ACCESS (SIGBUS)
Exception Codes: KERN_PROTECTION_FAILURE at 0x0000000000000011
Crashed Thread: 0 Dispatch queue: com.apple.main-thread
I think the problem is due to the fact that I'm using UIImage imageNamed, here is the code:
In ViewController.h:
UIImage *red;
UIImage *green;
UIImage *blue;
UIImageView *ballOne;
UIImageView *ballTwo;
UIImageView *ballThree;
UIImageView *ballFour;
// And declare UIImageView for other balls
int clr
In ViewController.m:
- (void)viewDidLoad {
...
red = [UIImage imageNamed: #"redTexture.png"];
green = [UIImage imageNamed: #"greenTexture.png"];
blue = [UIImage imageNamed: #"blueTexture.png"];
...
}
- (void)moveAll:(NSTimer *)theTimer{
...
// If UIImageView touches a corner, Do this:
clr = arc4random()%3 + 1;
switch (clr) {
case 1:
[ballOne setImage:red];
break;
case 2:
[ballOne setImage:green];
break;
case 3:
[ballOne setImage:blue];
break;
default:
break;
}
// And do this for the rest of 9 "balls"
}
Why does my App crash, and how do I solve it?

[UIImage imageNamed:] returns an autoreleased instance of a UIImage. That means that the memory will be released as soon as the event loop ends.
Yo need to retain those instance either by calling.
[[UIImage imageNamed:#"blabl.png"] retain]
or (preferred method) by setting up your blue, red, green members as property with
#property(nonatomic, retain) UIImage* red;
and your code will be like :
- (void)viewDidLoad {
...
self.red = [UIImage imageNamed: #"redTexture.png"];
self.green = [UIImage imageNamed: #"greenTexture.png"];
self.blue = [UIImage imageNamed: #"blueTexture.png"];
...
}
Of course do not forget to release them when your done otherwize you will have the opposite of what you have now : memory leaks.
to release red, call
[red release]
inthe dealloc method.

A bus error means that you're attempting to access memory that the CPU physically cannot access. You probably have a stray pointer.
Maybe try the memory allocation debugger?

Related

UIImage imageWithData memory leak

Using ASIHTTP, the code below is in the ImageDownloader class. I get a memory leak, which is added at the bottom, but I don't know why. I thought tempImage would be autoreleased without me doing anything?
- (void)requestFinished:(ASIHTTPRequest *)request
{
UIImage *tempImage = [UIImage imageWithData:[request responseData]];
if (tempImage.size.width > 250.0f && tempImage.size.height > 180.0f)
{
self.image = tempImage;
self.circleImage = [UIImage imageNamed:#"hover.png"];
if ([self.delegate respondsToSelector:#selector(addImageToModel:)])
[self.delegate addImageToModel:self];
}
else
{
if ([self.delegate respondsToSelector:#selector(badImage)])
[self.delegate badImage];
}
tempImage = nil;
}
self.image is getting set to tempImage, so it probably retains the image. Is it released anywhere?
You should not write this line :
tempImage = nil;
Since tempImage is a function scope variable, it will be taking care of by itself.
Further more, if self.image is (nonatomic, assign) that could be the origine of your leak.
About the stack trace image, is this from leak instruments, or memory instruments ?
Unfortunately, until you give away some more code, we won't be able to help you further.
As Thomas mentioned, it may be self.image retaining the image?
Have you considered waking up the zombies ? ;)
http://www.mikeash.com/pyblog/friday-qa-2011-05-20-the-inner-life-of-zombies.html
http://www.cocoadev.com/index.pl?NSZombieEnabled

Free memory after iphone animation

My app crashes due to memory building up after every animation.
Here is my sample code:
-(IBAction) shoot: (id)delegate{
[gun setImage:[UIImage imageNamed:#"animation_machin_guns_320x480_7.png"]];
UIImage *frame1 = [UIImage imageNamed:#"animation_machin_guns_320x480_1.png"];
UIImage *frame2 = [UIImage imageNamed:#"animation_machin_guns_320x480_2.png"];
UIImage *frame3 = [UIImage imageNamed:#"animation_machin_guns_320x480_3.png"];
UIImage *frame4 = [UIImage imageNamed:#"animation_machin_guns_320x480_4.png"];
UIImage *frame5 = [UIImage imageNamed:#"animation_machin_guns_320x480_5.png"];
UIImage *frame6 = [UIImage imageNamed:#"animation_machin_guns_320x480_6.png"];
UIImage *frame7 = [UIImage imageNamed:#"animation_machin_guns_320x480_7.png"];
gun.animationImages = [[NSArray alloc] initWithObjects:frame1, frame2, frame3, frame4, frame5, frame6, frame7,nil];
gun.animationDuration = 1;
gun.animationRepeatCount = 1;
[gun startAnimating];
[frame1 release];
[frame2 release];
[frame3 release];
[frame4 release];
[frame5 release];
[frame6 release];
[frame7 release];}
Releasing the frames doesn't seem to do the magic.
I tried using this http://kosmaczewski.net/projects/iphone-image-cache/ for image caching but i guess I don't know how to use it properly since the memory builds up faster than using imageNamed.
Replace [[NSArray alloc] initWithObjects:xxx]; with [NSArray arrayWithObjects:xxx];.
Currently, the array object is being retained twice (once effectively by alloc and once by gun.animationImages = xxx), but only released once (when the gun object is released, or the animationImages property is set to something new), meaning it will never be released.
The arrayWithObjects method returns an autoreleased object, meaning it doesn't need to be manually released by you.
If I were you I would think about only animating parts of the screen or perhaps compressing the images into low quality jpgs or something along those lines.

Objective C: EXC_BAD_ACCESS when generating a UIImage

I have a view that generates an image based on a series of layers. I have images for the background, for the thumbnail, and finally for an overlay. Together, it makes one cohesive display.
It seems to work a dream, except for when it doesn't. For seemingly no reason, I get an EXC_BAD_ACCESS on the specified line below after it's generated somewhere between 8 and 20 images. I've run it through the memory leak tool and allocation tool, and it's not eating up tons of memory and it's not leaking. I'm totally stumped.
Here's the relevant code:
- (UIImage *)addLayer:(UIImage *)layer toImage:(UIImage *)background atPoint:(CGPoint)point {
CGSize size = CGSizeMake(240, 240);
UIGraphicsBeginImageContext(size);
[background drawAtPoint:CGPointMake(0, 0)]; // <--- error here
[layer drawAtPoint:point];
UIImage* result = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return result;
}
// Build the layered image -- thingPage onto thingBackground,
// then the screenshot on that, then the thingTop on top of it all.
// thingBackground, thingPage and thingTop are all preloaded UIImages.
-(UIImage *)getImageForThing:(Thing *)t {
[self loadImageCacheIfNecessary];
if (!t.screenshot) {
return [UIImage imageNamed:#"NoPreview.png"];
} else {
UIImage *screenshot = t.screenshot;
UIImage *currentImage = [self addLayer:thingPage toImage:thingBackground atPoint:CGPointMake(0, 0)];
currentImage = [self addLayer:screenshot toImage:currentImage atPoint:CGPointMake(39, 59)];
currentImage = [self addLayer:thingTop toImage:currentImage atPoint:CGPointMake(0, 1)];
return currentImage;
}
}
I can't find anywhere that this is going wrong, and I've been tearing my hair out for a couple of hours on this. It's the final known bug in the system, so you can imagine how antsy I am to fix it! :-)
Thanks in advance for any help.
As to me, I always use -(void)drawInRect: instead of -(void)drawAtPoint:
CGRect rtDraw;
rtDraw.origin = CGPointZero;
rtDraw.size = size;
[background drawInRect:rtDraw];
[layer drawInRect:rtDraw];
And ....
The paint method with UIGraphicsBeginImageContext(size) and UIGraphicsEndImageContext() is not thread-safe.
Those functions will push or pop a context with stack struct, which is managed by system.
EXC_BAD_ACCESS is almost always due to accessing an object that has already been released. In your code this seems to be t.screenshot. Check creation (and retaining if it is an instance variable) of the object returned by Thing's screenshot property.
As it turns out, the error wasn't in the code I posted, it was in my caching of the thingBackground, thingPage and thingTop images. I wasn't retaining them. Here's the missing code, fixed:
-(void)loadImageCacheIfNecessary {
if (!folderBackground) {
thingBackground = [[UIImage imageNamed:#"ThingBack.png"] retain];
}
if (!folderPage) {
thingPage = [[UIImage imageNamed:#"ThingPage.png"] retain];
}
if (!folderTop) {
thingTop = [[UIImage imageNamed:#"ThingTop.png"] retain];
}
}
I will admit I'm still not comfortable with the whole retain/release/autorelease stuff in Objective C. Hopefully it'll sink in one day soon. :-)

iPhone app memory leak with UIImage animation? Problem testing on device

I have an animation which works fine in the simulator but crashes on the device. I am getting the following error...
Program received signal: “0”.
The Debugger has exited due to signal 10 (SIGBUS)
A bit of investigating suggests that the UIImages are not getting released and I have a memory leak. I am new to this so can someone tell me if this is the likely cause? If you could also tell me how to solve it then that would be amazing.
The images are 480px x 480px and about 25kb each. My code is below...
NSArray *rainImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"rain-loop0001.png"],
[UIImage imageNamed:#"rain-loop0002.png"],
[UIImage imageNamed:#"rain-loop0003.png"],
[UIImage imageNamed:#"rain-loop0004.png"],
[UIImage imageNamed:#"rain-loop0005.png"],
[UIImage imageNamed:#"rain-loop0006.png"],
//more looping images
[UIImage imageNamed:#"rain-loop0045.png"],
[UIImage imageNamed:#"rain-loop0046.png"],
[UIImage imageNamed:#"rain-loop0047.png"],
[UIImage imageNamed:#"rain-loop0048.png"],
[UIImage imageNamed:#"rain-loop0049.png"],
[UIImage imageNamed:#"rain-loop0050.png"],
nil];
rainImage.animationImages = rainImages;
rainImage.animationDuration = 4.15/2;
rainImage.animationRepeatCount = 0;
[rainImage startAnimating];
[rainImage release];
Thanks
I'm pretty sure you're crashing because [NSArray arrayWithObjects:] returns an auto-released object which you're storing to rainImage. Then at the bottom you're releasing rainImage again, thus over releasing it.
The root of the problem is that you are running out of main memory because you have too many decompressed images in memory, see my answer to uiimage-animation-causing-app-to-crash-memory-leaks for the reason you should not be using UIImageView.animationImages.

UIImage within Thread not being Released / Overwritten

This appears to be the the classic method for scanning images from the iPhone. I have a thread that is dispatched from the main thread to go and scan for Codes. It essentially creates a new UIImage each time then removes it.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
{
while (![thread isCancelled]) {
#ifdef DEBUG
NSLog(#"Decoding Loop");
#endif
// [self performSelectorOnMainThread:#selector(updateImageBuffer) withObject:nil waitUntilDone:YES];
CGImageRef cgScreen = UIGetScreenImage();
UIImage *uiimage = [UIImage imageWithCGImage:cgScreen];
if (uiimage){
CGSize size = [uiimage size];
CGRect cropRect = CGRectMake(0.0, 80.0, size.width, 360); // Crop to centre of the screen - makes it more robust
#ifdef DEBUG
NSLog(#"picked image size = (%f, %f)", size.width, size.height);
#endif
[decoder decodeImage:uiimage cropRect:cropRect];
}
[uiimage release];
CGImageRelease(cgScreen);
}
}
[pool release];
the problem is that the [pool release] causes an ERROR_BAD_EXC (that old classic) and the program bombs. I'm told that there is no need to call [uiimage release] as I havent explicitly allocated a UIImage but this doesn't seem to be the case. If I take that line out, Memory usage goes through the roof and the program quits dues to lack of memory. It appears I can't have this work the way I'd like.
Is there a way to create a UIImage "in-place"? I.e, have a buffer that is written to again and again as a UIImage? I suspect that would work?
Update!
Tried executing the UIKit related calls on the main thread as follows:
-(void)performDecode:(id)arg{
// Perform the decoding in a seperate thread. This should, in theory, bounce back with a
// decoded or not decoded message. We can quit at the end of this thread.
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
{
while (![thread isCancelled]) {
#ifdef DEBUG
NSLog(#"Decoding Loop");
#endif
[self performSelectorOnMainThread:#selector(updateImageBuffer) withObject:nil waitUntilDone:YES];
if (uiimage){
CGSize size = [uiimage size];
CGRect cropRect = CGRectMake(0.0, 80.0, 320, 360); // Crop to centre of the screen - makes it more robust
#ifdef DEBUG
NSLog(#"picked image size = (%f, %f)", size.width, size.height);
#endif
[decoder decodeImage:uiimage cropRect:cropRect];
}
}
}
[pool drain];
#ifdef DEBUG
NSLog(#"finished decoding.");
#endif
}
-(void) updateImageBuffer {
CGImageRef cgScreen = UIGetScreenImage();
uiimage = [UIImage imageWithCGImage:cgScreen];
//[uiimage release];
CGImageRelease(cgScreen);
}
No joy however as EXC_BAD_ACCESS rears its ugly head when one wishes to grab the "Size" of the UIImage
As has been stated by others, you should not release the UIImage returned from imageWithCGImage: . It is autoreleased. When your pool drains, it tries sending a release message to your already-released image objects, leading to your crash.
The reason why your memory usage keeps climbing is that you only drain the autorelease pool outside of the loop. Your autoreleased objects keep accumulating inside of the loop. (By the way, you need to release your autorelease pool at the end of that method, because it is currently being leaked.) To prevent this accumulation, you could drain the pool at regular intervals within the loop.
However, I'd suggest switching to doing [[UIImage alloc] initWithCGImage:cgScreen] and then releasing the image when done. I try to avoid using autoreleased objects whereever I can within iPhone applications in order to have tighter control over memory usage and overall better performance.
UIGetScreenImage() is private and undocumented so you flat-out cannot use it. Saying that nothing about it suggests that you now own CGImageRef cgScreen so why do you release it? You also have no way of knowing if it is thread safe and so should assume it isn't. You then go on to release the IImage *uiimage which you did not init, retain or copy, so again - you don't own it. Review the docs.
[uiimage release] is definitely wrong in this context. Also, Apple stresses that all UIKit methods must be executed on the main thread. That includes UIGetScreenImage() and +[UIImage imageWithCGImage:].
Edit: So you get an exception when calling -[UIImage size] on the wrong thread. This probably shouldn't surprise you because it is not permitted.
UIImage *uiimage = [[UIImage alloc] initWithCGImage: cgScreen];
Explicitly stating that I know best when to release the object seemed to work. Virtual Memory still increases but physical now stays constant. Thanks for pointing out the UIKit Thread Safe issues though. That is a point I'd missed but seems not affect the running at this point.
Also, I should point out, Red Laser and Quickmark both use this method of scanning camera information ;)