When I am scrolling images frequently in a UIScrollView then after some images, the next image takes time to load... it's not taking too much time but looks odd.
Suppose I have 27 images in a scrollView. When I start to scroll these images, for 1 or 2 images it scrolls smoothly but when I scroll again to see the 3rd image it takes time to load. Then when I start the images scrolling again from the 3rd image, it behaves like before.
I can't load all 27 images at a time or my app crashes.
When I slowly scroll the scrollview then I don't have this problem.
My code is below:
//Taking image view for 27 images;
int x=0;
for(int i = 1; i<=27; i++) {
imageView = [[UIImageView alloc] init];
imageView .frame = CGRectMake(x,0,768,1024);
imageView.tag=i;
imageView.image=nil;
imageView.userInteractionEnabled=YES;
[contentView addSubview:imageView];
x+=768;
}
//setContentOffset of the scrollView -->ContentView
[contentView setContentOffset: CGPointMake((imageNumber-1)*768, 0) animated: YES];
//desire image which i want to see from the start of the scrollview
pageNumber=imageNumber;
int pageBefore=pageNumber-1;
int pageAfter=pageNumber+1;
//Views for image
for( UIImageView * views in [contentView subviews]){
if(views.tag==pageNumber){
if(views.image==nil){
NSLog(#"entering");
views.image=[UIImage imageNamed:[ NSString stringWithFormat:#"%d.jpg",pageNumber]];
[views.image release];
}
}
if(views.tag==pageBefore){
if(views.image==nil){
views.image=[UIImage imageNamed:[ NSString stringWithFormat:#"%d.jpg",pageBefore]];
[views.image release];
}
}
if(views.tag==pageAfter){
if(views.image==nil){
views.image=[UIImage imageNamed:[ NSString stringWithFormat:#"%d.jpg",pageAfter]];
[views.image release];
}
}
My alarm bells rang when I saw this;
imageView .frame = CGRectMake(x,0,768,1024);
Apart from the space before .frame, are you saying that your images are 768x1024? That's HUGE and I suspect your problems are memory ones rather than code ones.
Be aware that in particular, using UIImage imageNamed: is likely to cause grief with such large images as that method caches the images in memory. You may wish to consider using alternative methods that load the image from a file each time.
You should try use the EGOImageView, it has caching build in which might help with your performance issues. You can implement a placeholder image to show the user that an image is being prepared for viewing. The image will load in another thread before being displayed, giving you smoother scrolling performance. The EGOImageView is part of the EGOImageLoading library.
https://github.com/tastefulworks/EGOImageLoading
As an alternative you could create your own lazy loading mechanism to increase scrolling performance. E.g. once a user stops scrolling for a second, start loading the image, otherwise display placeholder image if not yet the correct image is cached.
Edit: when thinking more about this issue, I realize caching won't help much (since you already load image from disk), but the asynchronous loading of images should help with the scroll performance, so make use of NSThread or NSOperation to load the image in a background thread, then notify the main thread that the image is loaded and ready for display.
Related
I am animating the ImageViews then the user taps a button. I have more than 40
images. The code I have used is
arr3 = [[NSArray alloc]initWithObjects:[UIImage imageNamed:#"Aperture_00000.png"],
[UIImage imageNamed:#"Aperture_00001.png"],
[UIImage imageNamed:#"Aperture_00002.png"],
...
[UIImage imageNamed:#"Aperture_00023.png"], nil];
imgv.animationImages = arr3;
imgv.animationDuration=2.0f;
imgv.animationRepeatCount =1;
The method to start the animation is:
-(void)animate {
[imgv startAnimating];
}
But it takes a lot of time when the user presses the button for the first time. What could be the solution for this?
The reason is following code:
arr3 = [[NSArray alloc]initWithObjects:[UIImage imageNamed:#"Aperture_00000"],[UIImage imageNamed:#"Aperture_00001"],[UIImage imageNamed:#"1.png",#"2.png",#"3png",#"4.png",#"5.png",#"6.png",#"7.png",#"8.png",#"9.png",#"10.png",#"11.png",#"12.png",#"13.png",#"14.png",#"15.png",];
What you can do is load this array somewhere else.
Note : This is a very memory consuming way of loading the images. Your app will definitely crash after you visit this class 2-3 times. Instead of this use some alternative. The easiest alternative I can suggest is load a image on UIImageView and change the image periodically. It'll give you animation effect.
I would suggest you rather doing it programmatically you should create animated gif image from the images. Here is online tool you can set speed and other parameters
http://picasion.com/
and use
https://github.com/arturogutierrez/Animated-GIF-iPhone
UIImageView category to display that gif image in that case you can save your CPU time.
Unhide the imageView when you want to play animation and hide when you want to stop.
I would suggest to give that at least a try.
I have a gallery view of photos that are downloaded from the internet so I used Enormego's EGOImageView. I noticed that when i scrolled down my tableview after the images were in the cache, the scrolling would lag. I immediately found that when the image was retrieved from the hard drive with return [UIImage imageWithContentsOfFile:cachePathForKey(key)]; it was working on the main thread so I added the operation to an NSOperationQueue. This reduced the lag by half but the scrolling still stuttered. After going through the code, I noticed that in the success method
- (void)imageLoaderDidLoad:(NSNotification*)notification {
if(![[[notification userInfo] objectForKey:#"imageURL"] isEqual:self.imageURL]) return;
UIImage* anImage = [[notification userInfo] objectForKey:#"image"];
self.image = anImage;
[self setNeedsDisplay];
if([self.delegate respondsToSelector:#selector(imageViewLoadedImage:)]) {
[self.delegate imageViewLoadedImage:self];
}
}
commenting out the self.image = anImage; got rid of the lag completely (but obviously I get no image). And as far as I can tell, if I want to alter the UI, it must be done in the main thread. Is there a way to set the image for the EGOImageView without it lagging the scrolling?
Note: the JPGs are around 50kB
Thanks
Subclass uitableViewCell and do your own drowing in drawContentView.
Resize images in background thread and then present them in cells.
P.S: if the code found on git hub is not good enough for you, try to write your own that suits your problem.
From what I understand, all the steps required to initiate an asynchronous disk query takes a couple milliseconds on the mainthread, and that is enough time for the scrolling to look like it stutters, so I decided to completely remove hard drive caching for large images and instead create an NSMutableDictionary which holds the UIImage as an object, and the NSURL.absoluteString as the key. This works seamlessly but obviously has the disadvantage of being a memory hog. I checked out the memory usage of some photo-sharing apps and I've been able to get the memory usage for the app to over 100MB so it seems everybody else is doing this.
I am using Apple's ScrollingSuite for displaying a large scrollview with a number of large images.(768 x1024) The image of an imageview is set by
controller.numberImage.image = [self.contentList objectAtIndex:page];
where, numberImage is an UIImageView and controller is an object of the viewcontroller which I am adding in the scrollview. I am setting the image as nil when the page is scrolled out of view by
controller.numberImage.image = nil;
But the problem is my app runs out of memory receiving Memory Warning when scrolled through the images. Each time a new image is shown, I can see memory increasing in instruments tool (Memory Tag 70) which on googling turns out ImageIO. Please help me with this
Thanks in advance
Try removing the imageView ( [controller.numberImage removeFromSuperview]; ), then adding it back before it is about to come into view ( [controller addSubview:[[UIImageView alloc] initWithImage:[self.contentList objectAtIndex:page]]]; ) possibly?
Various kinds of solution can be for such kinds of problem so...
I think you can remove the imageview like [controller.numberImage removeFromSuperview] and alloc the image again when you need the UImageView.it can be first solution.
At a time you can load 3 images if i explain then load the present image,previous image and next image.thats mean if you want to see the image 2 load at a time three images,image 1,image 2,and image 3. when you will scroll to next image then load image 2,image 3 and image 4 and dealloc the image 1...and so on...vice versa for loading image previous image loading.
the worst solution is try to decrease the image resolution without changing the size of the image.
So this one is pretty odd ad I'm not sure if the trouble is with the AssetsLibrary API, but I can't figure out what else might be happening.
I am loading an array with ALAssets using the -enumerateAssetsUsingBlock method on ALAssetsGroup. When it completes, I am loading a custom image scroller. As the scroller finishes scrolling, I use NSInvocationOperations to load the images for the currently visible views (pages) from the photo library on disk. Once the image is loaded and is cached, it notifies the delegate which then grabs the image from the cache and displays it in an image view in the scroller.
Everything works fine, but the time it takes from when -setImage: actually gets called to the time it actually shows up visibly on the screen is unbearable--sometimes 10 seconds or more to actually show up.
I have tried it both with and without image resizing which adds almost nothing to the processing time when I do the resizing. As I said, the slowdown is somewhere after I call -setImage on the image view. Is anyone aware of some sort of aspect of the AssetLibrary API that might cause this?
Here's some relevant code:
- (void)setImagesForVisiblePages;
{
for (MomentImageView *page in visiblePages)
{
int index = [page index];
ALAsset *asset = [photos objectAtIndex:index];
UIImage *image = [assetImagesDictionary objectForKey:[self idForAsset:asset]];
// If the image has already been cached, load it into the
// image view. Otherwise, request the image be loaded from disk.
if (image)
{
[[page imageView] setImage:image];
}
else {
[self requestLoadImageForAsset:asset];
[[page imageView] setImage:nil];
}
}
}
This will probably mess up any web searches looking to solve problems with the AssetsLibrary, so for that I apologize. It turns out that the problem wasn't the AssetsLibrary at all, but rather my use of multi-threading. Once the image finished loading, I was posting a notification using the default NSNotificationCenter. It was posting it on the background thread which was then updating (or trying to update, at least) the UIImageView with -setImage. Once I changed it to use -performSelectorOnMainThread and had that selector set the image instead, all was well.
Seems no matter how familiar I get with multi-threading, I still forget the little gotchas from time to time.
Im having a bit of trouble right now adding the same image multiple times and removing it all at one time after the gamelooop.
I manage to add the image by creating 1 UIImageview for every image but i know thats its not the practical way memory wise since im allocating a lot of uiimageview with the same image.
I use this code to load the image:
UIImageView *imgView1 = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"correct.png"]];
UIImageView *imgViewn = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"correct.png"]];
CGRect imgRect = CGRectMake((touch.x-20), (touch.y-20), 40, 40);
[imgView1 drawInRect:imgRect];
[imgViewn drawInRect:imgRect];
[imgView1 release]
[imgViewn release]
Basically i use this to add image base on the location of the usertouch made on the subview (with image). If the users set of touches are correct this is where the game loops and show another image for the user to touch.
But after the new image load the "correct.png" image which is added on the previous touch is still on view.
Can someone show me a correct way to do this coz im kinda new to programming but i know that im gonna have a memory problem later if i keep on allocating image every time a user touch the screen.
Thanks in advance.
If you're trying to merely move an image (or series of images) through each run of the gameloop, rather than creating and removing them all each time, perhaps create the series of N images only once.
When the touches or gameloop begins, draw the images in the rectangles you're calculating from the touch event, and then when the loop is over, set the hidden property on the object to YES or NO (not sure exactly what your objective is).
It's hard to give you code without more details on what you're doing, but the basic idea is this:
When you first start the program/view, create your N images, and set imageView.hidden = YES;
On each loop, call the [imageView drawInRect:imgRect] method for each image, and set imageView.hidden = NO;.
When the view/program is done, call the [imageView release] method on each object.