Where's the memory leak in my iPhone app? - iphone

It's a simple app that takes 30 pics from my Resources folder, puts them into an NSMutableArray during viewDidLoad, and then changes the pic based on accelerometer data. I have a UIImageView from IB covering the whole view, and when the accelerometer updates its info, it swaps the uiimageview.image to a diff pic. Works for about 10 seconds, and then crashes with this:
Program received signal: “0”.
Data Formatters temporarily unavailable, will re-try after a 'continue'. (Unknown error loading shared library "/Developer/usr/lib/libXcodeDebuggerSupport.dylib")
After looking around on here it sounds like it's a memory leak. Here's the code I'm using:
Interface:
{
UIAccelerometer *accel;
IBOutlet UIImageView *pic;
NSMutableArray *picArr;
}
Implementation:
- (void)viewDidLoad
{
[super viewDidLoad];
picArr = [[NSMutableArray alloc] init]; //array of pics to be used
NSString *path = [[NSString alloc] init]; //dynamic path of images to save to array
for (int i = 1; i <= 30; i++)
{
path = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"nativity_test_%i", i] ofType:#"jpg"];
[picArr addObject:[[UIImage alloc] initWithContentsOfFile:path]];
}
accel = [UIAccelerometer sharedAccelerometer];
accel.delegate = self;
accel.updateInterval = 0.5f;
[path release];
pic.image = [picArr objectAtIndex:15];
}
- (void)accelerometer:(UIAccelerometer *)accelerometer didAccelerate:(UIAcceleration *)acceleration
{
if(acceleration.y < 0.0f) //goes thru the tilted left pics
{
for (int i = 0; i <= 15; i++)
{
if( acceleration.y >= (-(15.0f-(double)i)/30.0f) && acceleration.y < (-(14.0f-(double)i)/30.0f) )
{
pic.image = [picArr objectAtIndex:i+1];
}
}
}
else if(acceleration.y > 0.0f) //goes thru tilted right pics
{
for (int i = 1; i <= 14; i++)
if( acceleration.y > ((double)i/30.0f) && acceleration.y <= ((double)(i+1)/30.0f) )
{
pic.image = [picArr objectAtIndex:i+15];
}
}
}
Please let me know if I left out any pertinent info.

This is not a crash caused by a memory leak, but by an overrelease of memory. Your crash is caused by this line:
[path release];
Remove that line and you should be fine. For some values of fine, anyway; most of what George says also applies.
The reason is that the path being released will be this one:
path = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"nativity_test_%i", i] ofType:#"jpg"];
That's an object with an effective retain count of zero. While it has a positive retain count, it's already been autoreleased and will be released when you return to the main event loop.
You should also remove this line:
NSString *path = [[NSString alloc] init]; //dynamic path of images to save to array
The reason is you're assigning the result of pathForResource to path, never actually using it. You'll need to declare path as a variable, of course. I suggest changing the pathForResource line to this:
NSString *path = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"nativity_test_%i", i] ofType:#"jpg"];
This is a smart change, as there's no reason you'd need this outside of the loop.
You should also fix this line:
[picArr addObject:[[UIImage alloc] initWithContentsOfFile:path]];
[UIImage alloc] returns an UIImage with an effective retain count of 1. Adding it to an array will increase that to two. If you're just releasing the array later, this will cause a memory leak. Instead:
[picArr addObject:[[[UIImage alloc] initWithContentsOfFile:path]] autorelease];
That will mean you're adding an UIImage with an effective retain count of 0 to the array, which will bump it to 1, making the array the only owner of the object. Later when the array goes away, so will most of the images. (The imageView will also own whichever is assigned to it.)
Don't be frustrated by this stuff: one day soon you'll just suddenly get it and wonder why it ever caused you headaches. :)

There's a couple of problems here:
1) You aren't releasing the UIImage objects you're adding to "picArr".
This line:
[picArr addObject:[[UIImage alloc] initWithContentsOfFile:path]];
Should be something like this instead:
UIImage *image = [[UIImage alloc] initWithContentsOfFile:path];
[picArr addObject: image];
[image release];
I believe you could also do:
[picArr addObject: [[[UIImage alloc] initWithContentsOfFile:path] autorelease]];
2) You don't need to do NSString *path = [[NSString alloc] init]; You can just do:
NSString *path;
You are giving the path variable a value inside that first loop so there's no need to alloc+init. Once you change this you can get rid of this line:
[path release];
3) I don't see where you are releasing "picArr" itself, you'll need to. You may be doing it already but didn't include that bit of code in your post.

Related

UIImageView and UIScrollView load lot of pictures

In my app, I use UIImageView and UIScrollView to show a lot of images (every time there are about 20 images and every image is about 600px*500px and size is about 600kb).
I use this code to accomplish this function:
// Here is pictures Data;
self.klpArry = self.pictureData;
CGSize size = self.klpScrollView1.frame.size;
for (int i=0; i < [klpArr count]; i++) {
UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake((size.width * i)+300, 20, 546, 546)];
NSString *filePath = [[NSBundle mainBundle] pathForResource:[klpArr objectAtIndex:i] ofType:#"jpg"];
UIImage *imageData = [[UIImage alloc]initWithData:[NSData dataWithContentsOfFile:filePath]];
[iv setImage:imageData];
iv.backgroundColor = [UIColor grayColor];
[self.klpScrollView1 addSubview:iv];
imageData = nil;
iv = nil;
iv.image = nil;
filePath = nil;
[imageData release];
[filePath release];
[iv release];
}
// show the picture in scrollview;
[self.klpScrollView1 setContentSize:CGSizeMake(size.width * numImage, size.height)];
self.klpScrollView1.pagingEnabled = YES;
self.klpScrollView1.showsHorizontalScrollIndicator = NO;
self.klpScrollView1.backgroundColor = [UIColor grayColor];
But every time I initialize this function, the memory will increase about 5MB. Actually I release UIImageView, UIimage and UIScrollView (vi.image=nil, [vi release]) but it doesn't work, the allocated memory is not getting released. BTW, I used my friend's code first vi.image = nil then vi = nil; but the pictures are not getting displayed on scrollview.
The main problem, as I see it, is that you're setting your local variables to nil and then you proceed to try to use those local variables in methods like release and the like, but because they've been set to nil, those methods now do nothing, and the objects with the +1 retainCount (or now +2 because you've added them to your view) are never released.
Thus, I'd suggest the following:
//Here is pictures Data;
self.klpArry = self.pictureData;
CGSize size = self.klpScrollView1.frame.size;
for (int i=0; i < [klpArr count]; i++) {
UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake((size.width * i)+300, 20, 546, 546)];
NSString *filePath = [[NSBundle mainBundle] pathForResource:[klpArr objectAtIndex:i] ofType:#"jpg"];
UIImage *imageData = [[UIImage alloc]initWithData:[NSData dataWithContentsOfFile:filePath]];
[iv setImage:imageData];
iv.backgroundColor = [UIColor grayColor];
[self.klpScrollView1 addSubview:iv];
// Don't set these to nil, or else subsequent release statements do nothing!
// These statements are actually not necessary because they refer to local
// variables so you don't need to worry about dangling pointers. Make sure
// you're not confusing the purpose of setting a pointer to nil in ARC to
// what you're doing in your non-ARC code.
//
// imageData = nil;
// iv = nil;
// You don't want to set this to nil because if iv is not nil, your image
// will be removed from your imageview. So, not only is this not needed,
// but it's undesired.
//
// iv.image = nil;
// This statement is not necessary for the same reason you don't do it
// to imageData or iv, either. This is probably even worse, though, because
// filePath is not a variable that you initialized via alloc. You should
// only be releasing things you created with alloc (or new, copy, mutableCopy,
// for which you issued a retain statement).
//
// filePath = nil;
[imageData release];
// filePath is a +0 retainCount already, so don't release. You only release
// those items for which you increased retainCount (e.g. via new, copy,
// mutableCopy, or alloc or anything you manually retained).
//
// [filePath release];
[iv release];
}
// show the picture in scrollview;
[self.klpScrollView1 setContentSize:CGSizeMake(size.width * numImage, size.height)];
self.klpScrollView1.pagingEnabled = YES;
self.klpScrollView1.showsHorizontalScrollIndicator = NO;
self.klpScrollView1.backgroundColor = [UIColor grayColor];
Thus, your code would be simplified (and corrected) to probably just be:
//Here is pictures Data;
self.klpArry = self.pictureData;
CGSize size = self.klpScrollView1.frame.size;
for (int i=0; i < [klpArr count]; i++) {
UIImageView *iv = [[UIImageView alloc] initWithFrame:CGRectMake((size.width * i)+300, 20, 546, 546)];
NSString *filePath = [[NSBundle mainBundle] pathForResource:[klpArr objectAtIndex:i] ofType:#"jpg"];
UIImage *imageData = [[UIImage alloc] initWithData:[NSData dataWithContentsOfFile:filePath]];
[iv setImage:imageData];
iv.backgroundColor = [UIColor grayColor];
[self.klpScrollView1 addSubview:iv];
[imageData release];
[iv release];
}
// show the picture in scrollview;
[self.klpScrollView1 setContentSize:CGSizeMake(size.width * numImage, size.height)];
self.klpScrollView1.pagingEnabled = YES;
self.klpScrollView1.showsHorizontalScrollIndicator = NO;
self.klpScrollView1.backgroundColor = [UIColor grayColor];
Or you could further simplify your code through the use of autorelease:
//Here is pictures Data;
self.klpArry = self.pictureData;
CGSize size = self.klpScrollView1.frame.size;
for (int i=0; i < [klpArr count]; i++) {
UIImageView *iv = [[[UIImageView alloc] initWithFrame:CGRectMake((size.width * i)+300, 20, 546, 546)] autorelease];
NSString *filePath = [[NSBundle mainBundle] pathForResource:[klpArr objectAtIndex:i] ofType:#"jpg"];
UIImage *imageData = [[[UIImage alloc] initWithData:[NSData dataWithContentsOfFile:filePath]] autorelease];
[iv setImage:imageData];
iv.backgroundColor = [UIColor grayColor];
[self.klpScrollView1 addSubview:iv];
}
// show the picture in scrollview;
[self.klpScrollView1 setContentSize:CGSizeMake(size.width * numImage, size.height)];
self.klpScrollView1.pagingEnabled = YES;
self.klpScrollView1.showsHorizontalScrollIndicator = NO;
self.klpScrollView1.backgroundColor = [UIColor grayColor];
By the way, the statement (with autorelease):
UIImage *imageData = [[[UIImage alloc] initWithData:[NSData dataWithContentsOfFile:filePath]] autorelease];
could probably be simplified to:
UIImage *imageData = [UIImage imageWithContentsOfFile:filePath];
This gives you a UIImage, with a +0 retainCount (i.e. you don't have to release it) from your file.
So, a few final observations:
You really should probably review and study the Advanced Memory Management Programming Guide. It's dense reading if you're new to memory management, but mastery of these concepts (especially in non-ARC code) is critical.
If you haven't, I'd encourage you to run your code through the static analyzer ("Product" - "Analyze" or shift+command+B). I'd be surprised if many (if not most) of these issues wouldn't have been identified for you by the analyzer. You should have zero warnings when you run your code through the analyzer.
If you want to take this to the next level, you might want to be far more conservative about your memory management. The governing principle would be a system design that only loads the images that are needed at the UI at any given time, which involves not only calvinBhai's excellent suggestion of lazy loading of images (i.e. don't load images into memory until your UI really needs them), but also a pro-active releasing images once they've scrolled off the screen. Maybe you don't need to worry about it in your app, because you're only dealing with 20 images at a time, but if any of your portfolios/galleries expanded to 100 or 1000 images, the idea of keeping all of those in memory at any given time is just a bad idea. This is a more advanced concept, so maybe you should focus on the basic memory management problems of your existing code first, but longer term, you might want to contemplate lazy loading and pro-active releasing of images.
If memory is your concern,
try lazy loading the images = Load the visible image, the next and previous image. You dont have to have all images added to your klpscrollview.
Once you figure out lazy loading the images onto your scrollview, then you can think of fixing the images not showing on your scrollview.
Easier would be to search for "lazy load uiimage uiscrollview"

How to correctly preload image arrays for animation

I have several animations which, when triggered, have varying lengths of (unintentional) delays before they execute.
Inside viewDidLoad i have something like:
NSString *fileName;
myArray = [[NSMutableArray alloc] init];
for(int i = 1; i < 285; i++) {
fileName = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"HD1.2 png sequence/HD1.2_%d", i] ofType:#"png"];
UIImage *image = [UIImage imageWithContentsOfFIle:fileName];
[humptyArray addObject:image];
//NSLog(#"Added object number %d: %#", i,regularImage);
}
falling.userInteractionEnabled = NO;
falling.animationImages = humptyArray;
falling.animationDuration = 6.3f;
falling.animationRepeatCount = 1;
I put in the NSLog so i could confirm that the array is populated with the images, which it is. When i want to trigger the animation i call [falling startAniamting]. Although the array has been preloaded with images there is still a delay between me triggering the animation and the animation executing.
What can i do so that there is no delay when i trigger the animation?
#autoreleasepool {
NSString *fileName;
humptyArray = [[NSMutableArray alloc] init];
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
for(int i = 1; i < 285; i++) {
fileName = [[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:#"HD1.2 png sequence/HD1.2_%d", i] ofType:#"png"];
UIImage *image = [UIImage imageWithContentsOfFIle:fileName];
[humptyArray addObject:image];
//NSLog(#"Added object number %d: %#", i,regularImage);
}
falling.userInteractionEnabled = NO;
falling.animationImages = humptyArray;
falling.animationDuration = 6.3f;
falling.animationRepeatCount = 1;
dispatch_async(dispatch_get_main_queue(), ^{
[humptyArray release];
});
});
}
Taken from my own answer in this other [SO question][1]
[1]: http://stackoverflow.com/a/11364856/253008
You will find that people on SO suggest using animationImages, but it can eat up all your system memory and it is not fast. Please have a look at my answer to smooth-video-looping-in-ios, it is talking about looping video but the issue is the same. Please also take a look at my answer to iphone-smooth-transition-from-one-video-to-another. There are 2 example xcode projects available at these links that show an implementation that will start playing quickly and loop without any glitch all without eating up all your memory and causing an app crash.

Xcode instruments generated lots of __CFCachedURLResponse memory leak

I have not used any NSURL API in my code but Xcode Instruments said my code has a lot of __CFCachedURLResponse memory leaks.
For instance,
Leaked Object # Address Size Responsible Library Responsible Frame
__CFCachedURLResponse,10 < multiple > 320 Bytes IPhoneUIBase
-[InterestGroupStockTR_RTS composeRTSData:]
The code is that after creating adding couple of objects to array, then call custom class.
NSMutableArray *arrCodes = [[NSMutableArray alloc] init];
for(int j = 0; j < countCode; j++ )
{
NSDictionary *pData = [listData objectAtIndex:j];
NSString *stockCode = [ NSString stringWithFormat:#"%#", pData ];
NSMutableDictionary *codeData2 = [[NSMutableDictionary alloc] initWithObjectsAndKeys:stockCode , #"acCode" , NULL ];
[arrCodes addObject:codeData2];
[codeData2 release];
}
[trData.dict setObject:arrCodes forKey:#"MULTI_SBR_ARRAYRP"];
[self requestWithData:trData];
[arrCodes removeAllObjects];
[arrCodes release];
Another question is Whats the difference between __CFCachedURLResponse and __CFURLCacheNode?. Some of classes have __CFURLCacheNode memory leak according to instrument.
Thanks

how to release memory from animating UIImage Array

I will like to know how to release the memory from the animating array, somehow in instruments the animating picture are eating up 24MB of real memory. what should i do to release the memory ? the total picture file size are about 3MB in Mac OS.
*EDIT:*Cool, i enabled the ARC setting in the build setting, no longer crashing...but memory usages still hovering around 80 - 120mb physical memory.....
this is the line that run for the image.
-(void)defaultSetup
{
self.imageArray = [[NSMutableArray alloc] initWithObjects:
[UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"default/d7.jpg"]],
[UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"default/d9.jpg"]],
[UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"default/d11.jpg"]],
[UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"default/d27.jpg"]],
[UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"default/d6.jpg"]],
nil];
self.defaultID = [[NSMutableArray alloc] initWithObjects:#"0",#"1",#"2",#"3",#"0",nil];
self.defaultImageCaption = [[NSMutableArray alloc] initWithObjects:#"Ver",#"Green",#"Red",#"Cru",#"East",nil];
NSUInteger count = [self.defaultID count];
NSLog(#"Count %i",[self.defaultID count]);
NSMutableArray *randomImgName = self.imageArray;
NSMutableArray *randomID = self.defaultID;
NSMutableArray *randomName = self.defaultImageCaption;
for (NSUInteger i = 0; i < count; ++i) {
// Select a random element between i and end of array to swap with.
int nElements = count - i;
int n = (arc4random() % nElements) + i;
[randomName exchangeObjectAtIndex:i withObjectAtIndex:n];
[randomImgName exchangeObjectAtIndex:i withObjectAtIndex:n];
[randomID exchangeObjectAtIndex:i withObjectAtIndex:n];
}
self.imageArray = randomImgName;
self.defaultID=randomID;
self.defaultImageCaption=randomName;
NSLog(#"default filename %#",self.defaultImageCaption);
NSLog(#"default ID %#",self.defaultID);
self.imageViewTop.alpha = 1.0;
self.imageViewBottom.alpha = 0.0;
self.imageViewBottom = [[[UIImageView alloc] initWithFrame:CGRectMake(0,44,320,367)] autorelease];
self.imageViewTop = [[[UIImageView alloc] initWithFrame:CGRectMake(0,44,320,367)] autorelease];
[self.view addSubview:imageViewTop];
[self.view addSubview:imageViewBottom];
self.buttonCaption = [UIButton buttonWithType:UIButtonTypeCustom];
//default placement
self.buttonCaption.frame = CGRectMake(245, 365, 70, 30);
//[buttonCaption setTitle:#"\u00A9" forState:UIControlStateNormal];
[self.buttonCaption addTarget:self action:#selector(buttonCheck) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:self.buttonCaption];
[self nextAnimation:buttonCaption.frame.size.width];
}
-(void)nextAnimation:(float)previousWidth {
//picture loop
imageViewTop.image = imageViewBottom.image;
imageViewBottom.image = [imageArray objectAtIndex:[imageArray count] - 1];
[imageArray insertObject:imageViewBottom.image atIndex:0];
[imageArray removeLastObject];
imageViewTop.alpha = 1.0;
imageViewBottom.alpha = 0.0;
//Name Caption
NSString * tempCaption = [defaultImageCaption objectAtIndex:[defaultImageCaption count]-1];
self.dID = [defaultID objectAtIndex:[defaultID count]-1];
// make the buttons content appear in the top-left
[buttonCaption setContentHorizontalAlignment:UIControlContentHorizontalAlignmentCenter];
[buttonCaption setContentVerticalAlignment: UIControlContentVerticalAlignmentCenter ];
[defaultImageCaption insertObject:tempCaption atIndex:0];
[defaultImageCaption removeLastObject];
[defaultID insertObject:dID atIndex:0];
[defaultID removeLastObject];
[UIView animateWithDuration:1 delay:2 options:0
animations:^{
[buttonCaption setTitle:tempCaption forState:UIControlStateNormal];
//NSLog(#"Name %#",tempCaption );
//NSLog(#"ID %#",dID);
}
completion:^(BOOL completed)
{
}];
Read up on Cocoa memory management. (I'm assuming you're not using ARC (automatic reference counting).) Btw, I'd consider using ARC, it makes your life easier. (It's a compile-time technology, so is backwards compatible with older iOS runtimes, but you don't get weak reference support on older iOS runtimes.)
To summarise the memory management rules: everything that increases your retain count on an object should be balanced by something that decreases the retain count at some point.
Things that increment the retain count:
self.propertyName = anInstance, when that property is declared with retain property.
[objectInstance retain].
[Class alloc], [Class new], [objectInstance copy] or variants beginning with copy.
Adding an object to a standard collection class (e.g. NSArray).
Things that decrement the retain count:
self.propertyName = <some other object instance or nil>, when that property is declared with retain property.
[objectInstance release]
[objectInstance autorelease] (causes a release at some later time).
Removing an object from a standard collection class (e.g. NSArray).
When something is created with alloc and init or an initWith* (as is done here with imageArray) you can release it with release:
[self.imageArray release];
If there's autorelease or retain calls involved, things can get a little bit more tricky. But they don't seem to come into play here.
If you load the images lazily (rather than getting array of UIImages imageArray make array of their locations) you can save lot of memory, and can easily clean up UIImage instances.
By doing this, the max images loaded in memory would not be more than 3; it can save RAM.
example as requested:
while initializing the array,
self.imageArray = [[NSMutableArray alloc] initWithObjects:
#"default/d7.jpg",
#"default/d9.jpg",
#"default/d11.jpg",
#"default/d27.jpg",
#"default/d6.jpg",
nil];
while loading actual image
NSString* imgPath = [imageArray objectAtIndex:[imageArray count] - 1];
imgPath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:imgPath];
imageViewBottom.image = [UIImage imageWithContentsOfFile:imgPath];
Let me know if it helps!

Removing UIImageView from UIScrollView

My app consists of an image gallery. It is a scroll view which displays pics retrieved from the sqlite db. User can scroll the images, add or delete images etc. I can add a picture to the gallery dynamically. But the problem comes when I need to implement the delete functionality. I use the following code but even after calling removeFromSuperView the image is not getting removed from the scrollview.
-(void)deleteDeck{
if(selectedEditDeck!=0){
[deck deleteSelectedDeck:selectedEditDeck]; //deleting from database
//problem starts here ***
[(UIImageView*)[decksGallery viewWithTag:selectedEditDeck-1]removeFromSuperview];
[self loadGallery];
selectedEditDeck=0;
//Ends here*****
[tableData release];
tableData=[NSMutableArray array];
[self showCardNamesinTable];
[aTableView reloadData];
}
I have already created the uiscrollview in the loadview method. Then to refresh the view after every deletion and addition of images so that I can display the updated gallery, I use the following piece of code:
-(void)loadGallery{ //Reloading all for adding a single deck image.
//Database part****
NSString *sqlStr = [NSString stringWithFormat:#"select first_card from decksTable"];
char *sql = (char*)[sqlStr UTF8String];
kidsFlashCardAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
NSMutableArray *galleryImagesArray=[appDelegate.dbConnection fetchColumnFromTable:sql col:0];
NSArray *sysPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES);
NSString *docDirectory = [sysPaths objectAtIndex:0];
numberofImages = [galleryImagesArray count];
printf("number is %d",numberofImages);//Database part of code ends here
//In the following fragment of code I add images to UIscrollView
for (int i = 0; i < [galleryImagesArray count]; i++) {
CGFloat yOrigin = i * 65;
NSString *filePath = [NSString stringWithFormat:#"%#/%#", docDirectory,[galleryImagesArray objectAtIndex:i]];
galleryImage = [[UIImageView alloc] initWithFrame:CGRectMake(yOrigin+140, 15,50,50 )];
//galleryImage.tag=[galleryImagesArray count];
galleryImage.tag=i;
printf("THE TAG IS %d",galleryImage.tag);
galleryImage.clipsToBounds=YES;
galleryImage.layer.cornerRadius=11.0;
galleryImage.backgroundColor=[UIColor clearColor];
galleryImage.image =[UIImage imageWithContentsOfFile:filePath];
[decksGallery addSubview:galleryImage];
[galleryImage release];
}
decksGallery.contentSize = CGSizeMake(115*[galleryImagesArray count], 80);
//[decksGallery reloadInputViews];
Make sure your [decksGallery viewWithTag:selectedEditDeck-1] is not returning nil and the image was actually deleted from your db before the refresh code running.
In addition, you are setting imageView.tag = i; in your creation code, since the i would be 0 which is the tag's default value for every UIView, you'd better fix your creation code as well.
If you just want to remove the image from your imageView, you can also do imageView.image = nil;
UIImageView*imageView = (UIImageView*)[decksGallery viewWithTag:selectedEditDeck-1];
[imageView removeFromSuperview];
imageView = nil;