how to animate a set of images, but I have a large set of images, 300 to be exact,
Background.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"001.jpg"],
[UIImage imageNamed:#"002.jpg"],
[UIImage imageNamed:#"003.jpg"],
[UIImage imageNamed:#"004.jpg"],
[UIImage imageNamed:#"005.jpg"],
[UIImage imageNamed:#"006.jpg"],
[UIImage imageNamed:#"007.jpg"],
[UIImage imageNamed:#"008.jpg"],
[UIImage imageNamed:#"009.jpg"],
[UIImage imageNamed:#"010.jpg"],
nil];
and I dont wanna go all the way up to 300 by typing, is there a solution for this?
Could I use a loop for this?
A loop might look like this
NSMutableArray *animationImages = [[NSMutableArray alloc] initWithCapacity:300];
for (int i = 1; i <= 300; i++) {
NSString *imageName = [NSString stringWithFormat:#"%03d.jpg", i];
[animationImages addObject:[UIImage imageNamed:imageName]];
}
Background.animationImages = animationImages;
The format specifier %03d means an integer padded with 0's to give a minimum field width of 3.
BUT
depending on the size of your images you may well run out of memory and have your app terminated.
Side note
Background is not a very good name for a variable on Objective-C. The convention is to start variable names with a lowercase letter and then use camel case after that.
NSMutableArray *array = [NSMutableArray array];
for (int i = 0; i < 300; i++)
{
NSString *imgName = [NSString stringWithFormat:#"%03d.jpg", i];
UIImage *img = [UIImage imageNamed:imgName];
[array addObject:img];
}
Background.animationImages = array;
Use GIF images to play animation. Playing GIF files with OpenGLES is the good practice and I believe it is the best way to play animation.
Follow the Git Link: https://github.com/jamesu/glgif
Related
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"
Actually i want to display iamge in UIImageView ...tat image names are getting from my database..so how to display image from getting string in an array in iphone
use this methods
UIImageView *imageView = [UIImageView alloc] initWithFrame:CGRectMake(0,0,320,480)];
imageView.animationImages = animationImages ;
imageView.animationRepeatCount = 2;
imageView.animationDuration= 4.0;
[imageView startAnimating];
animationImages is an Array containig UIImage Objects.
NSString *imageNameStr = [NSString stringWithFormat:#"%#",[imageNameArray objectAtIndex:index]];
UIImageView *myImage;
myImage=[[UIImageView alloc]initWithFrame:CGRectMake(00.0, 00.0, 320.0, 480.0)];
myImage.backgroundColor=[UIColor clearColor];
myImage.image=[UIImage imageNamed:imageNameStr];
[self.view addSubview:myImage];
hope it Help To you
You can use the following code.
NSString *str = [NSString stringWithFormat:#"%#",[arr_ArrayName objectAtIndex:index]];
NSString *path = [[ NSBundle mainBundle] pathForResource:str ofType:#"png"];
UIImage *temp = [UIImage imageWithContentsOfFile:path];
yourImageView.image = temp;
Pass the index value as an integer which image from array you want to display.
Edit:
Declare one integer temp in your view will appear. Set it's value to 0. temp = 0;
Then, inside your button action please write the below mentioned code:
-(void)buttonClick
{
NSString *selectedItem =[NSString stringWithFormat:#"%#",[colors objectAtIndex:temp]];
NSString *wrdstr = [[ NSBundle mainBundle] pathForResource:selectedItem ofType:#"png"];
UIImage *temp = [UIImage imageWithContentsOfFile:wrdstr];
imgshow.image = temp;
if(temp <= [colors count])
temp = temp + 1;
}
I have an animation of a menu background that is 21 frames. I load them into memory using the below code in the view's viewDidLoad method.
NSMutableArray *menuanimationImages = [[NSMutableArray alloc] init];
for( int aniCount = 0; aniCount < 21; aniCount++ )
{
NSString *fileLocation = [[NSBundle mainBundle] pathForResource: [NSString stringWithFormat: #"bg%i", aniCount + 1] ofType: #"png"];
NSData *imageData = [NSData dataWithContentsOfFile: fileLocation];
[menuanimationImages addObject: [UIImage imageWithData:imageData]];
}
settingsBackground.animationImages = menuanimationImages;
Unfortunately, doing [settingsBackground startAnimating]; doesn't work in the viewDidLoad method. Is there some way to preload the animation so there isn't a 1-3 second delay on first run?
I wouldn't normally recommend using imageNamed and relying on the in-built caching mechanisms. You'll find a lot of discussion on this if you search, but also it won't necessarily pre-render your images anyway.
I use the following code to pre-load and pre-render images so there is no delay when animating the first time through.
NSMutableArray *menuanimationImages = [[NSMutableArray alloc] init];
for (int aniCount = 1; aniCount < 21; aniCount++) {
NSString *fileLocation = [[NSBundle mainBundle] pathForResource: [NSString stringWithFormat: #"bg%i", aniCount + 1] ofType: #"png"];
// here is the code to pre-render the image
UIImage *frameImage = [UIImage imageWithContentsOfFile: fileLocation];
UIGraphicsBeginImageContext(frameImage.size);
CGRect rect = CGRectMake(0, 0, frameImage.size.width, frameImage.size.height);
[frameImage drawInRect:rect];
UIImage *renderedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
[menuanimationImages addObject:renderedImage];
}
settingsBackground.animationImages = menuanimationImages;
The problem with each of these answers is that the suggested "fix" is to preload all your image data into memory. That can and will result in crashes if your images are too big or there are too many images, see my answer for uiimage-animation-causing-app-to-crash-memory-leaks for more detailed info. The real fix is that you need to decompress the images but not hold them all in memory. Or, you can use a movie format that already does the decompression for all frames in one step, so that changing from frame to frame is not a costly operation.
The animationImages property of UIImageView requires an array of UIImage objects, not an array of NSData objects.
You may also want to set the duration and repeatCount, even though they have default values.
Example:
if (!self.idleView.animationImages) {
self.idleView.animationImages = [NSArray arrayWithObjects:[UIImage imageNamed:#"idle1.png"],
[UIImage imageNamed:#"idle2.png"],
[UIImage imageNamed:#"idle3.png"],
[UIImage imageNamed:#"idle4.png"],
[UIImage imageNamed:#"idle5.png"],
[UIImage imageNamed:#"idle6.png"],
[UIImage imageNamed:#"idle7.png"],
[UIImage imageNamed:#"idle8.png"],
[UIImage imageNamed:#"idle9.png"],
[UIImage imageNamed:#"idle10.png"],
[UIImage imageNamed:#"idle11.png"],
[UIImage imageNamed:#"idle12.png"],
[UIImage imageNamed:#"idle13.png"],
[UIImage imageNamed:#"idle14.png"],
[UIImage imageNamed:#"idle15.png"],
[UIImage imageNamed:#"idle16.png"],
[UIImage imageNamed:#"idle17.png"],
[UIImage imageNamed:#"idle18.png"],
[UIImage imageNamed:#"idle19.png"],
[UIImage imageNamed:#"idle20.png"]
, nil];
}
self.idleView.animationRepeatCount = 0;
self.idleView.animationDuration = 2.0;
[self.view addSubview:self.idleView];
[self.view sendSubviewToBack:self.idleView];
[self.idleView startAnimating];
Try the following code, normally you should have no delays. Also this code is simpler :
NSMutableArray *menuanimationImages = [[NSMutableArray alloc] initWithCapacity:21];
NSString *imageName;
for( int aniCount = 1; aniCount < 21; aniCount++ )
{
imageName = [NSString stringWithFormat:#"bg%d.png", aniCount];
[menuanimationImages addObject:[UIImage imageNamed:imageName]];
}
settingsBackground.animationImages = menuanimationImages;
// all frames will execute in 2 seconds
settingsBackground.animationDuration = 2.0;
// repeat the annimation forever
settingsBackground.animationRepeatCount = 0;
// start animating
[settingsBackground startAnimating];
enter code hereint quantity = [array count];
int i;
for (i=0; i<quantity; i++)
{
NSString *imageName = [NSString stringWithFormat:#"Car_%#.jpg", [[array objectAtIndex:i] objectForKey:#"CarName"]] ];
UIImage *img[i] = [UIImage imageNamed:imageName];
UIImageView *imgView[i] = [[UIImageView alloc] initWithImage:img[i]];
imgView[i].frame = CGRectMake(i*kWidth, 0, kWidth, kHeight);
[scrollView addSubview:imgView[i]];
[imgView[i] release];
}`enter code here`
Error: Variable-sized object may not be initialized. But why?
UIImage *img[i] = [UIImage imageNamed:imageName];
This declares a C-style array of size i and attempts to initialise it with an instance of UIImage. That doesn't make sense. What are you trying to do? Where is the rest of your code?
Edit:
Okay, I think I see what you are doing. Just get rid of all the places you have [i]. Inside the loop, you are only dealing with one item at a time, and even if you weren't, that's not how you use arrays.
You may want to try this:
int i;
for (i=0; i<quantity; i++)
{
NSString *imageName = [NSString stringWithFormat:#"Car_%#.jpg", [[array objectAtIndex:i] objectForKey:#"CarName"]] ];
UIImage *img = [UIImage imageNamed:imageName];
UIImageView *imgView = [[UIImageView alloc] initWithImage:img];
imgView.frame = CGRectMake(i*kWidth, 0, kWidth, kHeight);
[scrollView addSubview:imgView];
[imgView release];
}
You don't need to use img[i] in order to populate a scrollview with UIImageView.
Hey, trying to put a simple png sequence animation into my app. I have the first frame in place in IB, and the graphanimation outlet connected to it.
There are 54 pngs in the sequence with names "Comp 1_0000.png" to "Comp 1_00053.png"
Here's my code.
-(void)viewDidLoad{
for (int i=0; i<53; i++) {
graphanimation.animationImages = [NSArray arrayWithObjects:
[UIImage imageNamed:#"Comp 1_000%d.png",i]];
}
graphanimation.animationDuration = 1.00;
graphanimation.animationRepeatCount = 1;
[graphanimation startAnimating];
[self.view addSubview:graphanimation];
[super viewDidLoad];
}
I think something is wrong with the way I am referencing the image filenames with the i integer. Can someone help me sort this sucker out?
Thanks!
You can't pass a variable argument list and format arguments to [UIImage imageNamed:].
Try something like this perhaps?
...
NSMutableArray *array = [NSMutableArray arrayWithCapacity:54];
for (int i = 0; i < 54; ++i) {
NSString *name = [NSString stringWithFormat:#"Comp 1_000%d.png",i];
UIImage *image = [UIImage imageNamed:name];
[array addObject:image];
}
graphAnimation.animationImages = array;
...