ImageView Animation getting more Memory - objective-c

My application is in ARC.
I am using image Animation in imageView but after some period of time my application crashed with low memory error.
I am not getting any error message in Log but in Profile tool i am getting "Low Memory" message in allocation Part.
One code of my Animation is
ImageView= [[UIImageView alloc] init];
[self.view addSubview:ImageView];
ImageView.frame=CGRectMake(0, 0, 480, 342);
ImageView.animationImages = [NSArray arrayWithObjects:
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"image1" ofType:#"png"]],
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"image2" ofType:#"png"]],
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"image3" ofType:#"png"]],
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"image4" ofType:#"png"]],
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"image5" ofType:#"png"]],
[UIImage imageWithContentsOfFile:[[NSBundle mainBundle] pathForResource:#"image6" ofType:#"png"]],
nil];
[ImageView setAnimationRepeatCount:1];
ImageView.animationDuration =1.0;
[ImageView startAnimating];
If i comment this animation code then application is running correctly but i need more than 5 this type of animation in one view.
Any Link, tutorial, any Idea will be great help...

Why don't you try with a sprite? I've tried to animate with CALater (Core Animation Layer) and it works like a charm. I animate the 'contentsRect'. Short code example (CALayer subclass):
self.contents = [UIImage imageNamed:#"sprite-large.png"].CGImage;
NSMutableArray *frames = [NSMutableArray array]; // array of CGRect's
CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:#"contentsRect"];
anim.values = frames;
[self addAnimation:anim forKey:nil];
I've posted some code to GitHub a few weeks ago:
https://github.com/Gerharbo/sprite-animation-layer/
It provides an example sprite (not perfect, but it works) and some example code.
Have fun animating!
Gerhard

Gerharbo's method is basically a texture atlas but with one much bigger image. What I think you will find is that this kind of approach does not scale well when you try to use many images (for a long animation). You are already seeing crashes caused by running out of memory, so it would be a good idea to completely avoid UIImageView.animationImages. This blog post video-and-memory-usage-on-ios-devices describes why you cannot allocate memory to hold a bunch of images in main memory, which is exactly what you code above is trying to do. If you look around on SO you will find many other developers have ran into this same issue.

Related

Change UIImage imageOrientation metadata without affecting the image

I have an app which loads an image from the local disk and then displays it on a UIImageView. I want to set the image to aspect scale to fit.
The problem I'm having is that the imageOrientation is coming back as UIImageOrientationRight even though it's a portrait image and that's messing with how the aspect calculations are done.
I've tried a few methods of changing the meta data but both rotate the image when it gets displayed.
UIImageView *iv = [[UIImageView alloc] initWithFrame:self.frame.frame];
NSMutableString *path =[[NSMutableString alloc] initWithString: [[NSBundle mainBundle] resourcePath]];
[path appendString:#"/pic2.jpg"];
NSData *data = [NSData dataWithContentsOfFile:path];
UIImage *img = [UIImage imageWithData:data];
UIImage *fixed1 = [UIImage imageWithCGImage:[img CGImage]
scale:1.0
orientation: UIImageOrientationUp];
UIImage *sourceImage = img;
UIImage *fixed2 = [UIImage
imageWithCGImage:[img imageRotatedByDegrees:90].CGImage
scale:sourceImage.scale
orientation:UIImageOrientationUp];
iv.image = fixed1; // fixed2;
[iv setContentMode:UIViewContentModeScaleAspectFill];
[self.view addSubview:iv];
In the end I took a different approach and made the UIImageView 360 wide and placed it in the centre and this achieved the desired effect.

Memory leak not detected by static analyzer

I came across this piece of code
UIImageView *image = [[UIImageView alloc] initWithFrame:imageFrame];
[image setImage:[UIImage imageNamed:#"myImage"]];
[self.view addSubview:image];
image = nil;
Given that ARC is not used, I assume that it will lead to a memory leak on the image object.
Nevertheless the static analyzer doesn't catch that.
I'm wondering who is mistaken, the static analyzer or me, and I'd like a second opinion on that.
Does the above code actually leak?
It turned out the one mistaken was me (duh!)
The application I'm auditing is pretty large, and I missed the fact that the developers enabled ARC with the -fobjc-arc flag on specific classes, including the one the above snippet is taken from.
Long live to the static analyzer!
self.view has an array of pointers to its subviews that will keep your image accessible and keep the reference counter (used for ARC) above 0.
CGRect imageFrame = CGRectMake(100, 100, 100, 200);
UIImageView *image = [[UIImageView alloc] initWithFrame:imageFrame];
NSLog(#"image=%#", image);
[image setImage:[UIImage imageNamed:#"Default"]];
[self.view addSubview:image];
image = nil;
UIView *v = [[self.view subviews] objectAtIndex:0];
NSLog(#"v=%#", v);
When you put self.view = nil; the reference counter for image will drop and the memory will be free'd. I don't think you can create a leak this way :)

Removing UIImageView and getting the memory back (my memory is leaking)

I am making a simple drawing application, but a have problems with memory. After a few minutes using it, it just collapse, it makes the iPad very slow.
The lines the user create drawing are made of a UIImageView of 2x2 pixel, so it's this UIImageView is created several times:
UIImageView*dibujo = [[UIImageView alloc] initWithFrame:CGRectMake(x-1,y-1,2,2)];
dibujo.image = [UIImage imageNamed:#"pixelde2po2.png"];
tagdedibujo=tagdedibujo+1;
dibujo.tag=tagdedibujo;
[self.view addSubview:dibujo];
And it's being erased in this way:
for (int aa=ultimotag+1; aa<=tagdedibujo; aa++) {
//NSLog(#"destruyendo: %i", aa);
UIImageView*dibujo1 = (UIImageView *)[self.view viewWithTag:aa];
[UIView animateWithDuration:0.5 animations:^{
dibujo1.alpha=0;
}];
}
[self performSelector:#selector(matardibujo) withObject:(self) afterDelay:(0.51)];
ultimotag=tagdedibujo;
-(void) matardibujo{
for (int aa=ultimotag+1; aa<=tagdedibujo; aa++) {
[[self.view viewWithTag:aa] removeFromSuperview];
}
}
Even after erasing de draw (matardibujo) i don't get the memory back. Even it grows. So i think the erasing part is the one that's messing here.
I would preciate your help, i'm kind of new in this. Thanks :).
Could you replace dibujo.image = [UIImage imageNamed:#"pixelde2po2.png"]; with the following line of code to see if it resolves your issue?
NSString *fileName = [[NSBundle mainBundle] pathForResource:#"pixelde2po2" ofType:#"png"];
UIImage *image = [UIImage imageWithContentsOfFile:fileName];

iOS UIAppearance Error

I'm building a file management app, and I occasionally get the following error while calling a UIImagePickerController or a MPMediaPickerController:
*** -[_UIImageViewPretiledImageCacheKey hash]: message sent to deallocated instance 0x140dc0
I recently gave my app a custom theme using iOS 5's UIAppearance API and thats when I started getting this error. By guessing and checking, I found the problematic lines of my code that cause this error:
UIImage *backButtonImage = [[UIImage imageNamed:#"backButton.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(12, 16, 12, 8)];
[[UIBarButtonItem appearance] setBackButtonBackgroundImage:backButtonImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
UIImage *barButtonImage = [[UIImage imageNamed:#"barButton.png"] resizableImageWithCapInsets:UIEdgeInsetsMake(14, 12, 14, 12)];
[[UIBarButtonItem appearance] setBackgroundImage:barButtonImage forState:UIControlStateNormal barMetrics:UIBarMetricsDefault];
I have no idea how this code triggers the above error. Can you please explain to me the source of this error and provide a solution to fix it.
Thanks in advance for your help,
Guvvy
After some more thorough testing, I have reached the conclusion that this problem is limited to retina devices. The issue turned out to be in the #2x images. They had a odd numbered resolution (eg. 59px by 60px). All I did was recreate the image and changed the resolution to 60px by 60px and I never experienced the problem again.
I was kind of surprised by the solution as I saw no correlation between the error message and the line of code, but in the end, it was the images that caused this problem.
I had a similar problem, but my crash was caused by a resizable image in a UIImageView.
My resizable image has edge insets of top=30px, left=20px, bottom=1px, right=10px. The image is 43x45, so its resizable area is 13x14. I'm using iOS6, so I was able to workaround the problem by specifying UIImageResizingModeStretch as the resizingMode for -[UIImage resizableImageWithCapInsets:resizingMode:].
Works:
UIImage *image = [UIImage imageNamed:name];
UIImage *resizableImage = [image resizableImageWithCapInsets:edgeInsets resizingMode:UIImageResizingModeStretch];
Crashes with EXC_BAD_ACCESS or [_UIImageViewPretiledImageCacheKey hash]: message sent to deallocated instance 0xb14deb0 with NSZombieEnabled:
UIImage *image = [UIImage imageNamed:name];
UIImage *resizableImage = [image resizableImageWithCapInsets:edgeInsets];
I got the same for the following code
UIImage* image = [UIImage stretchableImageNamed:#"imageName"];
self.backgroundView = [[UIImageView alloc] initWithImage:image];
self.selectedBackgroundView = [[UIImageView alloc] initWithImage:image];
where self is UITableViewCell and stretchableImageNamed: is simply
+(UIImage*)stretchableImageNamed:(NSString*)name
{
UIImage *img = [UIImage imageNamed:name];
CGSize sz = img.size;
int left = (sz.width - 1.) / 2.;
int top = (sz.height - 1.) / 2.;
return [img resizableImageWithCapInsets:UIEdgeInsetsMake(top, left, top, left)];
}
this helped:
self.backgroundView = [[UIImageView alloc] initWithImage:[UIImage stretchableImageNamed:#"imageName"]];
self.selectedBackgroundView = [[UIImageView alloc] initWithImage:[UIImage stretchableImageNamed:#"imageName"]];

iOS: Add multiple UIImageViews programmatically in runtime

So, I'm doing a Breakout-clone on the iPhone. All elements except the bricks to hit, are created and working as expected with the NIB-file.
However, if I want to create different levels and run collision detection on the bricks, it seems stupid to add them in Interface Builder. How do I add them to the view in code?
I got an image called "brick.png" that I want to use with an UIImageView. Also, I want to have arrays and / or lists with these so I can build cool levels with pattern in the bricks and all :)
How do I do this in code?
#Mark is right, I would just add where the image need to be displayed!
UIImageView *imgView = [[[UIImageView alloc] initWithFrame:CGRectMake(10, 10, 100, 20)] autorelease];
NSString *imgFilepath = [[NSBundle mainBundle] pathForResource:#"brick" ofType:#"png"];
UIImage *img = [[UIImage alloc] initWithContentsOfFile:imgFilepath];
[imgView setImage:img];
[img release];
[self.view addSubview:imgView];
I tested the code and for me only shows when told the coordinates
It's really pretty easy. Here's an example of how you would create and display a UIImageView programatically...
UIImageView *imgView = [[[UIImageView alloc] init] autorelease];
NSString *imgFilepath = [[NSBundle mainBundle] pathForResource:#"brick" ofType:#"png"];
UIImage *img = [[UIImage alloc] initWithContentsOfFile:imgFilePath];
[imgView setImage:img];
[img release];
[self.view addSubview:imgView];
That's pretty much all there is to it.