Trouble with CALayer - ios

I have this code and XCode Analyze does not issue any warnings, but in the console every time I get a message:
2012-07-19 23:15:35.122 AttachIt [5725:907] Received memory warning.
Where is my mistake, point it, please.
for(int j=0;j<images;j++){
#autoreleasepool {
NSInteger currentRow = 0;
for(int k = 0; k<i;k++)
currentRow = currentRow + [[assetGroups objectAtIndex:k] numberOfAssets];
asset = [assets objectAtIndex:j+currentRow];
float size = [self getRandomNumberBetweenMin:60.0 andMax:65.0];
CGRect rect;
if(iPad)
rect = CGRectMake(10+j*35.5, 75-size, size, size);
else
rect = CGRectMake(10+j*26, 75-size, size, size);
UIImageView *temp = [[UIImageView alloc] initWithImage:[UIImage imageWithCGImage:[asset thumbnail]]];
temp.frame = rect;
temp.layer.backgroundColor = [UIColor blueColor].CGColor;
temp.layer.shadowOffset = CGSizeMake(0, 3);
temp.layer.shadowRadius = 5.0;
temp.layer.shadowColor = [UIColor blackColor].CGColor;
temp.layer.shadowOpacity = 0.8;
temp.layer.masksToBounds = NO;
temp.layer.borderColor = [[UIColor whiteColor] CGColor];
temp.layer.borderWidth = 2;
[temp setTransform:CGAffineTransformMakeRotation(degreesToRadians([self getRandomNumberBetweenMin:-5 andMax:5]))];
temp.layer.shouldRasterize = TRUE;
[albumRow addSubview:temp];
}
}

Memory warnings are not the result of mistakes; they are a normal part of running on iOS. You're allocating a bunch of stuff, so getting a memory warning is not surprising.
If you're having problems where your app is being killed by the system due to excess memory usage, you might consider populating those images over time rather than in a loop. You could accomplish this via an NSOperationQueue or similar mechanism to load the images one at a time.
In any case, you could use the "Allocations" or "Activity Monitor" instruments to see if your memory usage is growing and by how much.

Related

iOS UIImageView memory not getting deallocated on ARC

I want to animate an image view in circular path and on click of image that image view need to change the new image. My problem is the images i allocated to the image view is not deallocated. And app receives memory warning and crashed. I surfed and tried lot of solutions for this problem but no use. In my case i need to create all ui components from Objective c class. Here am posting the code for creating image view and animation.
#autoreleasepool {
for(int i= 0 ; i < categories.count; i++)
{
NSString *categoryImage = [NSString stringWithFormat:#"%#_%ld.png",[categories objectAtIndex:i],(long)rating];
if (paginationClicked) {
if([selectedCategories containsObject:[categories objectAtIndex:i]]){
categoryImage = [NSString stringWithFormat:#"sel_%#",categoryImage];
}
}
UIImageView *imageView = [[UIImageView alloc] init];
imageView.image = [self.mySprites objectForKey:categoryImage];
imageView.contentMode = UIViewContentModeScaleAspectFit;
imageView.clipsToBounds = NO;
[imageView sizeToFit];
imageView.accessibilityHint = [categories objectAtIndex:i];
// imageView.frame = CGRectMake(location.x+sin(M_PI/2.5)*(self.view.frame.size.width*1.5),location.y+cos(M_PI/2.5)*(self.view.frame.size.width*1.5) , 150, 150);
imageView.userInteractionEnabled = YES;
imageView.multipleTouchEnabled = YES;
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self
action:#selector(categoryTapGestureCaptured:)];
singleTap.numberOfTapsRequired = 1;
[imageView addGestureRecognizer:singleTap];
[categoryView addSubview:imageView];
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
UIBezierPath *path = [UIBezierPath bezierPath];
[path addArcWithCenter:location
radius:self.view.frame.size.width*1.5
startAngle:0.8
endAngle:-0.3+(0.1*(i+1))
clockwise:NO];
animation.path = path.CGPath;
imageView.center = path.currentPoint;
animation.fillMode = kCAFillModeForwards;
animation.removedOnCompletion = NO;
animation.duration = 1+0.25*i;
animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
// Apply it
[imageView.layer addAnimation:animation forKey:#"animation.trash"];
}
}
And this is the code to change the image on click.
for (UIImageView *subview in subviews) {
NSString *key = [NSString stringWithFormat:#"%#_%ld.png",subview.accessibilityHint,(long)rating];
if ([SelectedCategory isEqualToString:subview.accessibilityHint]) {
NSString *tempSubCategory = [categoryObj objectForKey:SelectedCategory];
if([selectedCategories containsObject:SelectedCategory]){
subview.image = [self.mySprites objectForKey:key];
[selectedCategories removeObject:SelectedCategory];
if (tempSubCategory.length != 0) {
subCategoriesAvailable = subCategoriesAvailable-1;
}
[self showNoPagination:subCategoriesAvailable+2];
}else{
if(selectedCategories.count != 2){
key = [NSString stringWithFormat:#"sel_%#",key];
subview.image = [self.mySprites objectForKey:key];
[selectedCategories addObject:SelectedCategory];
if ([SelectedCategory isEqualToString:#"Other"]) {
[self showCommentDialog];
}else{
if (tempSubCategory.length != 0) {
subCategoriesAvailable = subCategoriesAvailable+1;
}
[self showNoPagination:subCategoriesAvailable+2];
}
}
}
[self disableCategories];
break;
}
}
And i don't know what am doing wrong here. I tried nullifying on for loop but no use.
Code which i used for removing the image view
UIView *categoryView = [self.view viewWithTag:500];
NSArray *subviews = [categoryView subviews];
for (UIImageView *subview in subviews) {
if(![selectedCategories containsObject:subview.accessibilityHint]){
[subview removeFromSuperview];
subview.image = Nil;
}
}
Adding sprite reader code for reference
#import "UIImage+Sprite.h"
#import "XMLReader.h"
#implementation UIImage (Sprite)
+ (NSDictionary*)spritesWithContentsOfFile:(NSString*)filename
{
CGFloat scale = [UIScreen mainScreen].scale;
NSString* file = [filename stringByDeletingPathExtension];
if ([[UIScreen mainScreen] respondsToSelector:#selector(displayLinkWithTarget:selector:)] &&
(scale == 2.0))
{
file = [NSString stringWithFormat:#"%##2x", file];
}
NSString* extension = [filename pathExtension];
NSData* data = [NSData dataWithContentsOfFile:[NSString stringWithFormat:#"%#.%#", file,extension]];
NSError* error = nil;
NSDictionary* xmlDictionary = [XMLReader dictionaryForXMLData:data error:&error];
NSDictionary* xmlTextureAtlas = [xmlDictionary objectForKey:#"TextureAtlas"];
UIImage* image = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:#"%#.%#", file,[[xmlTextureAtlas objectForKey:#"imagePath"]pathExtension]]];
CGSize size = CGSizeMake([[xmlTextureAtlas objectForKey:#"width"] integerValue],
[[xmlTextureAtlas objectForKey:#"height"] integerValue]);
if (!image || CGSizeEqualToSize(size, CGSizeZero)) return nil;
CGImageRef spriteSheet = [image CGImage];
NSMutableDictionary* tempDictionary = [[NSMutableDictionary alloc] init];
NSArray* xmlSprites = [xmlTextureAtlas objectForKey:#"sprite"];
for (NSDictionary* xmlSprite in xmlSprites)
{
CGRect unscaledRect = CGRectMake([[xmlSprite objectForKey:#"x"] integerValue],
[[xmlSprite objectForKey:#"y"] integerValue],
[[xmlSprite objectForKey:#"w"] integerValue],
[[xmlSprite objectForKey:#"h"] integerValue]);
CGImageRef sprite = CGImageCreateWithImageInRect(spriteSheet, unscaledRect);
// If this is a #2x image it is twice as big as it should be.
// Take care to consider the scale factor here.
[tempDictionary setObject:[UIImage imageWithCGImage:sprite scale:scale orientation:UIImageOrientationUp] forKey:[xmlSprite objectForKey:#"n"]];
CGImageRelease(sprite);
}
return [NSDictionary dictionaryWithDictionary:tempDictionary];
}
#end
Please help me to resolve this. Thanks in advance.
It looks like all the images are being retained by the dictionary(assumption) self.mySprites, as you are loading them with the call imageView.image = [self.mySprites objectForKey:categoryImage];
If you loaded the images into the dictionary with +[UIImage imageNamed:], then the dictionary initially contains only the compressed png images. Images are decompressed from png to bitmap as they are rendered to the screen, and these decompressed images use a large amount of RAM (that's the memory usage you're seeing labeled "ImageIO_PNG_Data"). If the dictionary is retaining them, then the memory will grow every time you render a new one to the screen, as the decompressed data is held inside the UIImage object retained by the dictionary.
Options available to you:
Store the image names in the self.mySprites dictionary, and load the images on demand. You should be aware that +[UIImage imageNamed:] implements internal RAM caching to speed things up, so this might also cause memory issues for you if the images are big, as the cache doesn't clear quickly. If this is an issue, consider using +[UIImage imageWithContentsOfFile:], although it requires some additional code (not much), which doesn't cache images in RAM.
Re-implement self.mySprites as an NSCache. NSCache will start throwing things out when the memory pressure gets too high, so you'll need to handle the case that the image is not there when you expect it to be, and load it from disk (perhaps using the above techniques)
CAKeyframeAnimation inherits from CAPropertyAnimation which in tern is inherited from CAAnimation.
If you see the delegate of CAAnimation class, it is strongly referenced as written below as it is declared -
/* The delegate of the animation. This object is retained for the
* lifetime of the animation object. Defaults to nil. See below for the
* supported delegate methods. */
#property(strong) id delegate;
Now you have added the reference of animation on imageView.layer, doing so the reference of imageView.layer will be strongly retained by CAAnimation reference.
Also you have set
animation.removedOnCompletion = NO;
which won't remove the animation from layer on completion
So if you are done with a image view then first removeAllAnimations from its layer and then release the image view.
I think as the CAAnimation strongly refers the imageView reference(it would also have increased it's retain count) and this could be the reason that you have removed the imageView from superview, after which it's retain count would still not be zero, and so leading to a leak.
Is there any specific requirement to set
animation.removedOnCompletion = NO;
since, setting
animation.removedOnCompletion = YES;
could solve the issue related to memory leak.
Alternatively, to resolve memory leak issue you can remove the corresponding animation on corresponding imageView' layer, by implementing delegate of CAAnimation, like as shown below -
/* Called when the animation either completes its active duration or
* is removed from the object it is attached to (i.e. the layer). 'flag'
* is true if the animation reached the end of its active duration
* without being removed. */
- (void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag {
    if (flag) {
        NSLog(#"%#", #"The animation is finished. Do something here.");
    }
//Get the reference of the corresponding imageView
    [imageView.layer removeAnimationForKey:#"animation.trash"];
}
UIView *categoryView = [self.view viewWithTag:500];
NSArray *subviews = [categoryView subviews];
for (UIImageView *subview in subviews) {
if(![selectedCategories containsObject:subview.accessibilityHint]){
[subview.layer removeAnimationForKey:#"animation.trash"]; // either this
//or// [subview.layer removeAllAnimations]; //alternatively
[subview removeFromSuperview];
subview.image = Nil;
}
}

UIImageView uses a lot of memory

I'm creating some kind of image gallery. User can swipe between photo's. (Its just the concept, i know there are good library's out there that can handle this, but it's just to explain the concept).
I'm loading in 3 UIImageView, and i'm constantly reusing them. (Lazy loading). Problem is, when i change the image dynamiccaly from one imageview, and keep changing it, the memory is filling up. It's like it does not releases previous attached images. I'm using an array of UIImages that I already downloaded from some kind of web service.
As i load my view, i'm allocing and init my UIImageView, then I add it to the view.
UIImageView* _imgView;
NSArray* _imgArray;
So this array contains UIImage
-(void)changeImageIndex: (int) i
{
_imgView.image = [_imgArray objectAtIndex:i];
}
if i keep changing the imageindex, memory just gets filled up and filled up.. :s.
My project is ARC enabled.
Somebody has a clue how to solve it?
The image is added (actually changed) by this method:
-(void)setCurrentMovie:(GFilm*)film
{
_currentMovie = nil;
_currentMovie = film;
_posterView.image = nil;
[_youtubeView loadHTMLString:#"" baseURL:nil];
[_youtubeView stopLoading];
[_youtubeView setDelegate:nil];
[[NSURLCache sharedURLCache] removeAllCachedResponses];
[_scrollView setContentOffset:CGPointMake(0, 0) animated:NO];
CGFloat leftHeight = 0.f;
_leftView.frame = CGRectMake(10, 10, 110, 205);
leftHeight += _leftView.frame.size.height;
_posterView.frame = CGRectMake(0, 0, _leftView.frame.size.width, _leftView.frame.size.height - 40);
GImage* img = (GImage*)[_currentMovie.imageList objectAtIndex:0];
//_posterView.image = img.localImage;
//#autoreleasepool {
_posterView.image = [UIImage imageWithData:UIImagePNGRepresentation(img.localImage)];
_btnVertoningen.frame = CGRectMake(0, _posterView.frame.origin.y + _posterView.frame.size.height + 5, _leftView.frame.size.width, 35);
_posterView.userInteractionEnabled = YES;
UITapGestureRecognizer *singleTap = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(posterClick)];
singleTap.numberOfTapsRequired = 1;
[_posterView addGestureRecognizer:singleTap];
[_leftView addSubview:_posterView];
CGFloat rightHeight = 0.f;
_rightView.frame = CGRectMake(_leftView.frame.origin.x + _leftView.frame.size.width + 5, _leftView.frame.origin.y, self.view.frame.size.width - (_leftView.frame.size.width + _leftView.frame.origin.x) - 15, 1);
_lblRegie.frame = CGRectMake(0, rightHeight, 48, 16);
NSMutableString* text = [[NSMutableString alloc]init];
NSArray* arr = _currentMovie.directorList;
etc.....
}
Probably your app have memory leak. Try use imageWithContentsOfFile instead of imageNamed:
_imgView.image = [UIImage imageWithContentsOfFile:imagePath];
Another possibility to have memory leaks with ARC is using a separate thread without an autorelease pool set up. Check this link:
https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html:

UILabel (CALayer) is using large amounts of virtual memory

In Xcode and Instruments I see UILabel (CALayer) using large amounts of virtual memory (Anonymous VM). I see about 235 KB of virtual memory per UILabel.
I think this perhaps is a new issue with iOS 7.1 or 7.1.1.
Is this expected?
I created a simple program that creates 500 UILabels and Instruments shows 115MB of memory used. At about 1500 labels the application is terminated by the OS.
for (int i = 0; i < 500; i++)
{
index = (int)[self.items count];
index++;
frame = CGRectMake(10.0, 20, 300.0, 50.0);
UILabel *newLabel = [[UILabel alloc] initWithFrame:frame];
newLabel.text = [NSString stringWithFormat:#"This is text for label: %d", index];
newLabel.backgroundColor = [UIColor whiteColor];
[self.view addSubview:newLabel];
[self.items setObject:newLabel forKey:[NSNumber numberWithInteger:index]];
}
Thoughts?
UILabel, and any view that uses drawRect (at least on iOS 7+) is backed by a texture, so every UILabel will use a lot of memory, the larger the label, the more memory used.
I've found this especially painful in my photo editing extension for You Doodle which allows adding text in the Photos app. Unfortunately I have to greatly restrict the scale range of the text because photo extensions are much more limited to memory usage than regular apps before they crash.
This can easily be verified by running instruments and allocating a bunch of large UILabel's and setting their text and ensuring they are all visible, i.e.:
CGRect f = CGRectMake(0.0.0f, 0.0f, 300.0f, 300.0f);
for (NSInteger i = 0; i < 100; i++)
{
UILabel* l = [[UILabel alloc] initWithFrame:f];
l.backgroundColor = UIColor.blueColor;
l.textColor = UIColor.whiteColor;
l.text = #"UILabel text for the memory test";
l.numberOfLines = 0;
[self.view addSubview:l];
}
When reporting this kind of thing (to Stack Overflow or to Apple), you really should eliminate unnecessary excess code. This code is sufficient to reproduce the phenomenon:
for (int i = 0; i < 500; i++)
{
CGRect frame = CGRectMake(10.0, 20, 300.0, 50.0);
UILabel *newLabel = [[UILabel alloc] initWithFrame:frame];
newLabel.backgroundColor = [UIColor whiteColor];
[self.view addSubview:newLabel];
}
That causes the app to use 129MB on my machine. (No need to use Instruments: Xcode now shows memory usage directly.)
My first response was: "I guess I don't find this terribly surprising. If you change the frame to a smaller rect, less memory is used. Views are expensive! They are backed by a bitmap."
However, if you change the UILabel to a plain UIView, only 13MB is used. I think that's a sufficient difference to warrant filing a bug.

Poor UIScrollView Performance with Many Subviews

I am building a simple app which displays a users Contacts with photos like this -
The contacts are each a positioned subview, with another subview inside containing a UIImageView to generate the images w/rounded corners and a UILabel.
Scrolling becomes rather choppy on both iPhone 4/4s and iPhone 5, however, even with only 6-7 contacts. Also, the choppyness seems to be constant. It doesn't matter if they have 8 contacts or 500 contacts, it doesn't get worse or better either way.
Does anybody know why this might be? The algorithm that generated this grid can be seen below. Are there any specific properties on the UIScrollView I haven't set, etc?
- (void) generateContactGrid
{
CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeople(self.addressBook);
CFIndex nPeople = ABAddressBookGetPersonCount(self.addressBook);
int peopleInARow = 0;
int maxPeopleInARow = 3;
int positionFromTop = 20;
int IMAGE_SIZE = 70;
float animationOffset = .5;
float animationOffsetChange = .3;
float animationDuration = .5;
int scaleOffset = 40;
int screenWidth = 320;
int startingPositionFromLeft = 26;
int positionFromLeft = startingPositionFromLeft;
int topOffset = 40;
int leftOffset = 26;
int numberOfRows = 0;
UIView *contactContainer;
UIImage* image;
CALayer *l;
NSString *name;
NSString *lastName;
NSString *firstName;
UIImageView *newimageview;
UILabel *label;
UIView *contactImageContainer;
for ( int i = 0; i < nPeople; i++ )
{
ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i);
firstName = (__bridge_transfer NSString*)ABRecordCopyValue(person,kABPersonFirstNameProperty);
lastName = (__bridge_transfer NSString*)ABRecordCopyValue(person, kABPersonLastNameProperty);
name = [NSString stringWithFormat:#"%# %#", firstName, lastName];
if(ABPersonHasImageData(person)){
NSLog(#"Current Contact Being Generated: %#", name);
image = [UIImage imageWithData:(__bridge NSData *)ABPersonCopyImageData(person)];
NSLog(#"Contact's Position From Left: %i", positionFromLeft);
newimageview = [[UIImageView alloc] initWithFrame:CGRectMake(-scaleOffset/2, -scaleOffset/2, IMAGE_SIZE+scaleOffset, IMAGE_SIZE+scaleOffset)];
newimageview.contentMode = UIViewContentModeScaleAspectFit;
[newimageview setImage: image];
contactContainer = [[UIView alloc] initWithFrame:CGRectMake(positionFromLeft, positionFromTop + 20, IMAGE_SIZE, 200)];
contactImageContainer = [[UIView alloc] initWithFrame:CGRectMake(0, 0, IMAGE_SIZE, IMAGE_SIZE)];
contactImageContainer.clipsToBounds = YES;
l = [contactImageContainer layer];
[l setMasksToBounds:YES];
[l setCornerRadius:IMAGE_SIZE/2];
[l setBorderWidth:0.0];
[l setBorderColor:[[UIColor colorWithRed:234.0/255.0 green:234.0/255.0 blue:234.0/255.0 alpha:.6] CGColor]];
[contactImageContainer addSubview:newimageview];
[contactContainer addSubview:contactImageContainer];
label = [[UILabel alloc] initWithFrame: CGRectMake(0, IMAGE_SIZE + 10, IMAGE_SIZE, 20)];
label.text = firstName;
label.backgroundColor = [UIColor colorWithRed:0/255.0 green:0/255.0 blue:0/255.0 alpha:0];
label.textColor = [UIColor whiteColor];
[label setTextAlignment:NSTextAlignmentCenter];
[label setFont:[UIFont fontWithName:#"Arial-BoldMT" size:14]];
[contactContainer addSubview:label];
contactContainer.alpha = 0;
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:animationDuration];
[UIView setAnimationDelay:animationOffset];
animationOffset+= animationOffsetChange;
[UIView setAnimationCurve:UIViewAnimationCurveEaseOut];
contactContainer.alpha = 1;
CGRect temp = contactContainer.frame;
temp.origin.y = positionFromTop;
contactContainer.frame = temp;
[UIView commitAnimations];
if(peopleInARow >= 2){
positionFromTop += IMAGE_SIZE + topOffset;
peopleInARow = 0;
positionFromLeft = startingPositionFromLeft;
numberOfRows++;
} else {
peopleInARow += 1;
positionFromLeft += IMAGE_SIZE + leftOffset;
}
[self.scrollView addSubview:contactContainer];
[self.scrollView bringSubviewToFront:contactContainer];
}
}
NSLog(#"%i", numberOfRows);
self.scrollView.contentSize = CGSizeMake(screenWidth, 150 * numberOfRows);
}
Use Instruments to measure what exactly makes your app slow. Everything else is just guessing.
But I will guess anyways. This most likely is the masking you apply to your UIImageViews. Try disabling that and see if it is still slow (and by see I mean measure, of course). If that is indeed the cause there are two things you can try. First you can set the shouldRasterize property of the masked layer and see if that actually is enough. This could make things worse though if your layers get changed a lot. The other option would be to render those masked pictures with Core Graphics instead of using layers.

Image scrollview crashes

I've implemented a scrollview with paging to scroll between some images (graphs) at full page (like the Photo app installed in the iPhone).
I found the code below that use the classical 3 pages solution (I made some small modification for my application) but, even if it "works", the scrolling seems to be slow and often after I've scrolled some images the application crashes.
I'm using Xcode 4.2 with ARC option enabled and testing both on an iPad device.
Images (10 jpg) are 2048x1539 with a mean dimension of 200/250Kb each.
Is there anyone that can help me in finding the cause of the problem ?
Thanks,
Corrado
const int numImages = 10;
const float kPageWidth = 1024.0f;
const float kPageHeight = 768.0f;
- (void)viewDidLoad {
[super viewDidLoad];
scroll.contentSize = CGSizeMake(kPageWidth * numImages, kPageHeight);
imageview1 = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, kPageWidth, kPageHeight)];
imageview2 = [[UIImageView alloc] initWithFrame:CGRectMake(kPageWidth, 0, kPageWidth, kPageHeight)];
imageview3 = [[UIImageView alloc] initWithFrame:CGRectMake(kPageWidth * 2, 0, kPageWidth, kPageHeight)];
scroll.contentOffset = CGPointMake(0, 0);
[imageview1 setImage:[UIImage imageNamed:#"grafico_0.jpg"]];
imageview1.contentMode = UIViewContentModeScaleAspectFit;
[imageview1 setTag:1];
imageview2.contentMode = UIViewContentModeScaleAspectFit;
[imageview2 setTag:2];
imageview3.contentMode = UIViewContentModeScaleAspectFit;
[imageview3 setTag:3];
[scroll addSubview:imageview1];
[scroll addSubview:imageview2];
[scroll addSubview:imageview3];
}
- (void)scrollViewDidScroll:(UIScrollView*)scrollView {
const CGFloat currPos = scrollView.contentOffset.x;
const NSInteger selectedPage = lroundf(currPos * (1.0f / kPageWidth));
const NSInteger zone = 1 + (selectedPage % 3);
const NSInteger nextPage = selectedPage + 1;
const NSInteger prevPage = selectedPage - 1;
/// Next page
if (nextPage < numImages)
{
NSInteger nextViewTag = zone + 1;
if (nextViewTag == 4)
nextViewTag = 1;
UIImageView* nextView = (UIImageView*)[scrollView viewWithTag:nextViewTag];
nextView.frame = (CGRect){.origin.x = nextPage * kPageHeight, .origin.y = 0.0f, kPageHeight, kPageWidth};
NSString *str = [NSString stringWithFormat:#"grafico_%d.jpg", nextPage];
UIImage* img = [UIImage imageNamed:str];
nextView.image = img;
}
/// Prev page
if (prevPage >= 0)
{
NSInteger prevViewTag = zone - 1;
if (!prevViewTag)
prevViewTag = 3;
UIImageView* prevView = (UIImageView*)[scrollView viewWithTag:prevViewTag];
prevView.frame = (CGRect){.origin.x = prevPage * kPageHeight, .origin.y = 0.0f, kPageHeight, kPageWidth};
NSString *str = [NSString stringWithFormat:#"grafico_%d.jpg", prevPage];
UIImage* img = [UIImage imageNamed:str];
prevView.image = img;
}
}
You should not use imageNamed: for the loading of your large images, because that method caches the images and should only be used for small images that you use multiple times in your App (like images for buttons etc.). That method is notorious for causing memory problems when used with many large images.
Switch to imageWithContentsOfFile: instead. Loading your images with that methods secures that the images are not cached and the memory is freed after you do not use that images any more.
If the scrolling seems to be sluggish you can move the loading of the image to a background thread using performSelectorInBackground:
[self performSelectorInBackground:#selector(retrieveImageData:) withObject:imagePath];
the loading of the UIImage happens in this method:
- (void)retrieveImageData:(NSString *)imagePath {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
[self performSelectorOnMainThread:#selector(imageDataRetrieved:) withObject:image waitUntilDone:NO];
[pool release];
}
and the attachment of the image to the UIImageView on the main thread (UI manipulations must not happen on a background Thread):
- (void)imageDataRetrieved:(UIImage)*image {
yourImageView.image = image;
}

Resources