I am reading images from document directory in a loop.
for(iArrCount=0;iArrCount<[arrImages count];iArrCount++)
{
UIButton *btnImage = [UIButton buttonWithType:UIButtonTypeCustom];
btnImage.frame = CGRectMake(xRow, yRow, width, height);
[btnImage addTarget:self action:@selector(imageDetails:) forControlEvents:UIControlEventTouchUpInside];
btnImage.tag = iCount;
if(iCount<[arrImages count])
{
NSString *workSpacePath=[[self applicationDocumentsDirectory] stringByAppendingPathComponent:[arrImages objectAtIndex:iCount]];
[btnImage setBackgroundImage:[UIImage imageWithData:[NSData dataWithContentsOfFile:workSpacePath]] forState:UIControlStateNormal];
[scrollImages addSubview:btnImage];
}
}
On doing so, control goes to didRecieveMemoryWarning
and application crashes. If I replace the image by a image from resource folder, application does not crashes. Why so?
The problem is that your buttons are maintaining a reference to the full resolution image. What you will need to do is scale down the image to your button dimensions and set that scaled down image as your button background. Something like this should do the trick:
Create a category on UIImage... Let's call it UIImage+Scaler.h
// UIImage+Scaler.h
#import <UIKit/UIKit.h>
@interface UIImage (Scaler)
- (UIImage*)scaleToSize:(CGSize)size;
@end
And the implementation:
// UIImage+Scaler.m
#import "UIImage+Scaler.h"
#define kBitsPerComponent 8
#define kBitmapInfo kCGImageAlphaPremultipliedLast
- (UIImage*)scaleToSize:(CGSize)size
{
CGBitmapInfo bitmapInfo = kBitmapInfo;
size_t bytesPerRow = size.width * 4.0;
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(NULL, size.width,
size.height, kBitsPerComponent,
bytesPerRow, colorSpace, bitmapInfo);
CGRect rect = CGRectMake(0.0f, 0.0f, size.width, size.height);
CGContextDrawImage(context, rect, self.CGImage);
CGImageRef scaledImageRef = CGBitmapContextCreateImage(context);
UIImage* scaledImage = [UIImage imageWithCGImage:scaledImageRef];
CGImageRelease(scaledImageRef);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
return scaledImage;
}
OK, now back to your code. Like the other posters said you'll need an autorelease pool.
CGSize buttonSize = CGSizeMake(width, height);
for(iArrCount=0;iArrCount<[arrImages count];iArrCount++)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
UIButton *btnImage = [UIButton buttonWithType:UIButtonTypeCustom];
btnImage.frame = CGRectMake(xRow, yRow, width, height);
[btnImage addTarget:self
action:@selector(imageDetails:)
forControlEvents:UIControlEventTouchUpInside];
btnImage.tag = iCount;
if(iCount<[arrImages count])
{
NSString *workSpacePath=[[self applicationDocumentsDirectory]
stringByAppendingPathComponent:
[arrImages objectAtIndex:iCount]];
UIImage* bigImage = [UIImage imageWithData:[NSData
dataWithContentsOfFile:workSpacePath]];
UIImage* smallImage = [bigImage scaleToSize:buttonSize];
[btnImage setBackgroundImage:smallImage forState:UIControlStateNormal];
[scrollImages addSubview:btnImage];
}
[pool drain]; // must drain pool inside loop to release bigImage
}
Hope this solves for problem.
Put your for
loop in an autorelease pool:
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for(...)
{
....
}
[pool release];
Use NSAutoreleasePool. Keep your code inside an autoreleasepool.
for(iArrCount=0;iArrCount<[arrImages count];iArrCount++)
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
......
......
[pool drain];
}