I want photo slider like whts app has. It should access all the pics or some of the pics from in build photo library and it should be scrollable using scroll view.
I have tried with different photo viewer but everything has memory issue. So not sure if anyone has it's working solution. Really appreciate your help.
Thank you,
Ankita
This is working almost fine, but one small problem with backbord direction scrolling. Just try this out may be you can find some direction to go and may be find better solution using it.
(Have used ELCImagePicker to show first time all images and then on selecting one present the scrollview to show large images at a time 10 images are shown also have tweak the delegate method of ELCImagePickerController to get the index of selected image)
At first load ie when select image from ELCImagePickerController
- (void)elcImagePickerController:(ELCImagePickerController *)picker didFinishPickingMediaWithInfo:(NSArray *)info selectedIndex:(NSInteger)_index {
[self dismissModalViewControllerAnimated:NO];
for (UIView *v in [scrollview subviews]) {
[v removeFromSuperview];
}
infoItems = [[NSArray alloc]initWithArray:info];
CGRect workingFrame = scrollview.frame;
workingFrame.origin.x = 0;
int indexFrame = picker.selectedIndex;
newIndex = indexFrame;
for(int i = 0; i < [info count]; i++)
{
NSDictionary *dict = [info objectAtIndex:i];
UIImageView *imageview = [[UIImageView alloc] initWithImage:[dict objectForKey:UIImagePickerControllerOriginalImage]];
[imageview setContentMode:UIViewContentModeScaleAspectFit];
imageview.frame = workingFrame;
imageview.tag = i;
if(i >= indexFrame && i <= indexFrame + 9)
{
[scrollview addSubview:imageview];
workingFrame.origin.x = workingFrame.origin.x + workingFrame.size.width;
}
}
[scrollview setPagingEnabled:YES];
[scrollview setContentSize:CGSizeMake(workingFrame.origin.x, workingFrame.size.height)];
[scrollview scrollRectToVisible:CGRectMake(0, 0, workingFrame.size.width, workingFrame.size.height) animated:NO];
self.scrollview.hidden = NO;
self.pageControll.hidden = NO;
self.pageControll.numberOfPages = [[scrollview subviews]count];
index = 0;
lastContentOffset = scrollview.contentOffset.x;
NSLog(#"lastContentOffset %.2f",lastContentOffset);
}
After that on scrollViews delegate method
-(void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
NSLog(#"ScrollViewDidEndDecelerating is called with subview(s) %d",[[scrollview subviews]count]);
if(lastContentOffset < scrollView.contentOffset.x)
{
index += (int)(scrollview.contentOffset.x - lastContentOffset)/scrollview.frame.size.width;
newIndex += (int)(scrollview.contentOffset.x - lastContentOffset)/scrollview.frame.size.width;
self.pageControll.currentPage = index;
NSLog(#"Index incremented %d \n newIndex %d",index,newIndex);
if(index == [[scrollView subviews]count]-1)
{
if(newIndex < [infoItems count]-1)
{
[self performSelector:#selector(reloadScrollViewWithNewImages)];
}
}
[Appirater userDidSignificantEvent:YES];
}
else if(lastContentOffset > scrollView.contentOffset.x)
{
index -= (int)(lastContentOffset - scrollview.contentOffset.x)/scrollview.frame.size.width;
newIndex -= (int)(int)(lastContentOffset - scrollview.contentOffset.x)/scrollview.frame.size.width;
self.pageControll.currentPage = index;
NSLog(#"Index decremented %d \n newIndex %d",index,newIndex);
if(index == 0)
{
if(newIndex > 0)
{
newIndex -= 9;
if(newIndex < 0)
newIndex = 0;
[self performSelector:#selector(reloadScrollViewWithNewImages)];
}
}
[Appirater userDidSignificantEvent:YES];
}
lastContentOffset = scrollView.contentOffset.x;
NSLog(#"New lastContentOffset %.2f",lastContentOffset);
}
and the method used for reload the scrollView is as follow
-(void)reloadScrollViewWithNewImages
{
for (UIView *v in [scrollview subviews]) {
[v removeFromSuperview];
}
CGRect workingFrame = scrollview.frame;
workingFrame.origin.x = 0;
NSLog(#"reloadScrollView newIndex %d",newIndex);
int indexFrame = newIndex;
for(int i = 0; i < [infoItems count]; i++)
{
NSDictionary *dict = [infoItems objectAtIndex:i];
UIImageView *imageview = [[UIImageView alloc] initWithImage:[dict objectForKey:UIImagePickerControllerOriginalImage]];
[imageview setContentMode:UIViewContentModeScaleAspectFit];
imageview.frame = workingFrame;
imageview.tag = i;
if(i >= indexFrame && i <= indexFrame + 9)
{
[scrollview addSubview:imageview];
workingFrame.origin.x = workingFrame.origin.x + workingFrame.size.width;
}
}
[scrollview setPagingEnabled:YES];
[scrollview setContentSize:CGSizeMake(workingFrame.origin.x, workingFrame.size.height)];
[scrollview scrollRectToVisible:CGRectMake(0, 0, workingFrame.size.width, workingFrame.size.height) animated:NO];
self.scrollview.hidden = NO;
self.pageControll.hidden = NO;
index = 0;
self.pageControll.numberOfPages = [[scrollview subviews]count];
NSLog(#"number %d",[[scrollview subviews]count]);
lastContentOffset = scrollview.contentOffset.x;
NSLog(#"reloadScrollView's lastContentOffset %.2f",lastContentOffset);
}
and all used properties and private ivars declared in .h file's interface part required in this code are
Private ivars
NSInteger index;
float lastContentOffset;
Properties
#property (nonatomic,strong) IBOutlet UIScrollView *scrollview;
#property (strong, nonatomic) NSArray *infoItems;
#property (assign, atomic) int newIndex;
Happy Coding :)
You can use CATiledLayer to draw image. CATiledLayer can be used to increase the performance of paging, panning, and zooming with high-resolution images or large sets of photos.
As i commented above you can go by reusable view approach means at a time only three imagview or view will be in memory. Let say you are showing photo number:2 so, you should have to keep photo:1,2 and3 in memory(i.e. to avoid flicker) no need to load all photos at a time. Suppose you are scrolling to photo number:3 then your logic should discard photo number:1 and should load photo number:2,3,4. If you are still not getting or don't know how to do this programmatically then don't worry. Apple's good sample code is available that is doing all you want.
Sample code
In above sample code they have displayed two way of displaying image.
One is directly showing/setting the image into image view.
Second is with drawing image with TileView using this method: - (void)displayTiledImageNamed:(NSString *)imageName size:(CGSize)imageSize
If you are thinking lot of about memory then definitely you have to use second approach.
Related
I like the kindle for iPhone's navigation - the one which enables you to just slide the titles in the navigation bar to move from one view to another. (I'm attaching the image)
However, I was searching for a long time yesterday and I cannot find anybody who has done something similar.
Would you have any ideas on how to do this?
UPDATE: May 24, 2012
So now I have codes. Thanks to this tutorial http://bit.ly/xNOiqd. (I just copied most of his code.) But I still cannot achieve the same effect that the kindle app's nav bar has. I can now peek on the left and the right item but my scroll view skips the labels which are on the odd indices of my array. Let's say I have 'Favourites', 'All Products', and 'Categories'. When I swipe left, I move from 'Favourites' to 'Categories' and skip 'All Products'
Here's the code.
#pragma mark -
- (void)loadVisiblePages {
// First, determine which page is currently visible
CGFloat pageWidth = self.scrollView.frame.size.width;
NSInteger page = (NSInteger)floor((self.scrollView.contentOffset.x * 2.0f + pageWidth) / (pageWidth * 2.0f));
// Update the page control
self.pageControl.currentPage = page;
// Work out which pages we want to load
NSInteger firstPage = page - 1;
NSInteger lastPage = page + 1;
// Purge anything before the first page
for (NSInteger i=0; i<firstPage; i++) {
[self purgePage:i];
}
for (NSInteger i=firstPage; i<=lastPage; i++) {
[self loadPage:i];
}
for (NSInteger i=lastPage+1; i<self.pageImages.count; i++) {
[self purgePage:i];
}
}
- (void)loadPage:(NSInteger)page {
if (page < 0 || page >= self.pageImages.count) {
// If it's outside the range of what we have to display, then do nothing
return;
}
// Load an individual page, first seeing if we've already loaded it
UIView *pageView = [self.pageViews objectAtIndex:page];
if ((NSNull*)pageView == [NSNull null]) {
CGRect frame = self.scrollView.bounds;
//frame.origin.x = frame.size.width * page;
frame.origin.x = (frame.size.width /2) * page;
frame.origin.y = 0.0f;
//
frame = CGRectInset(frame, 10.0f, 0.0f);
//self.scrollView.bounds = frame;
/* == orig line
UIImageView *newPageView = [[UIImageView alloc] initWithImage:[self.pageImages objectAtIndex:page]];
newPageView.contentMode = UIViewContentModeScaleAspectFit;
newPageView.frame = frame;
*/
UILabel *newPageView = [[UILabel alloc] init];
newPageView.text = [self.pageImages objectAtIndex:page];
newPageView.textColor = [UIColor whiteColor];
//newPageView.textColor = [UIColor grayColor];
newPageView.textAlignment = UITextAlignmentCenter;
newPageView.font = [UIFont fontWithName:#"Helvetica-Bold" size:20];
[newPageView setBackgroundColor:[UIColor clearColor]];
newPageView.frame = frame;
[self.scrollView addSubview:newPageView];
[self.pageViews replaceObjectAtIndex:page withObject:newPageView];
}
}
- (void)purgePage:(NSInteger)page {
if (page < 0 || page >= self.pageImages.count) {
// If it's outside the range of what we have to display, then do nothing
return;
}
// Remove a page from the scroll view and reset the container array
UIView *pageView = [self.pageViews objectAtIndex:page];
if ((NSNull*)pageView != [NSNull null]) {
//[pageView removeFromSuperview];
//[self.pageViews replaceObjectAtIndex:page withObject:[NSNull null]];
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
//scroll view stuff
self.scrollView.delegate = self;
//attempt to make size of scrollview smaller
//CGRect frame = self.scrollView.bounds;
//frame = CGRectInset(frame, 10.0f, 0.0f);
//CGFloat width = self.scrollView.frame.size.width/2.0f;
self.pageImages = [NSArray arrayWithObjects:#"Favourites", #"All Products", #"Categories",#"Boo yah", nil];
NSInteger pageCount = self.pageImages.count;
// Set up the page control
self.pageControl.currentPage = 0;
self.pageControl.numberOfPages = pageCount;
// Set up the array to hold the views for each page
self.pageViews = [[NSMutableArray alloc] init];
for (NSInteger i = 0; i < pageCount; ++i) {
[self.pageViews addObject:[NSNull null]];
}
}
- (void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
CGSize pagesScrollViewSize = self.scrollView.frame.size;
//self.scrollView.contentSize = CGSizeMake(pagesScrollViewSize.width * self.pageImages.count, pagesScrollViewSize.height);
//This modifies the size of the scroll view, I can't seem to get it right
self.scrollView.contentSize = CGSizeMake((pagesScrollViewSize.width / 1.50f )* self.pageImages.count, self.scrollView.frame.size.height);
// Load the initial set of pages that are on screen
[self loadVisiblePages];
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
// Load the pages which are now on screen
[self loadVisiblePages];
}
iCarousel is a nice open source project with lots of scroll types.
A paged scrollview and AQGridView most likely. If not, it would be an acceptable reverse-engineering attempt anyways.
The code below is supposed to display a series of images in an infinite, connected loop. Instead, it just displays a totally white field. Thanks to Aaron Hayman for getting me this far.
- (void)layoutScrollImages
{
//Arrangement
NSArray *imageViews = [NSArray arrayWithObjects:#"image1.png", #"image2.png", #"image3.png", nil];
CGRect cRect = scrollView1.bounds;
UIImageView *cView;
for (int i = 0; i < imageViews.count; i++)
{
cView = [imageViews objectAtIndex:i];
cView.frame = cRect;
[scrollView1 addSubview:cView];
cRect.origin.x += cRect.size.width;
}
scrollView1.contentSize = CGSizeMake(cRect.origin.x, scrollView1.bounds.size.height);
scrollView1.contentOffset = CGPointMake(scrollView1.bounds.size.width, 0); //should be the center page in a 3 page setup
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
scrollView1.contentOffset = CGPointMake(scrollView.bounds.size.width, 0);
}
FOLLOW UP:
Nothing I'm doing is making any difference. Currently, my code looks like this, but I'm changing everything I can think of to no avail.
- (void)layoutScrollImages
{
//Horizontal arrangement
NSObject *image1 = #"image1.png";
NSObject *image2 = #"image2.png";
NSObject *image3 = #"image3.png";
NSArray *imageViews = [NSArray arrayWithObjects:image1, image2, image3, nil];
CGRect cRect = scrollView1.bounds;
UIImageView *cView;
for (int i = 0; i < imageViews.count; i++)
{
cView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:[imageViews objectAtIndex:i]]];
cView.frame = cRect;
[scrollView1 addSubview:cView];
cRect.origin.x += cRect.size.width;
}
scrollView1.contentSize = CGSizeMake(cRect.origin.x, scrollView1.bounds.size.height);
scrollView1.contentOffset = CGPointMake(scrollView1.bounds.size.width, 0); //should be the center page in a 3 page setup
[self layoutScrollImages];
}
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
scrollView1.contentOffset = CGPointMake(scrollView.bounds.size.width, 0);
}
You never initiate a UIImageView. You want to do something like this:
NSArray *imageViews = [NSArray arrayWithObjects:#"image1.png", #"image2.png", #"image3.png", nil];
CGRect cRect;
UIImageView *cView;
for (int i = 0; i < imageViews.count; i++)
{
cView = [[UIImageView alloc] initWithImage:[UIImage imageName:[imageViews objectAtIndex:i]]];
cRect = cView.frame;
cRect.origin.x += scrollView1.frame.size.width;
cView.frame = cRect;
[scrollView1 addSubview:cView];
NSLog(#"imageView bounds: %#", NSStringFromCGRect(cView.frame));
}
Edit:
Try the above and see if anything shows up. Here are some thoughts:
Are you sure that you aren't setting the imageView to have 0 height/width? I threw in an NSLog statement to the loop. It will print the frame of the imageView.
Have you tried adding the images to self.view instead of scrollView1? That would be a good way to make sure that the problem doesn't have to do with the frame of scrollView1. Or use the following:
NSLog(#"imageView bounds: %#", NSStringFromCGRect(scrollView1.frame));
I've implemented an infinite UIScrollView that contains UIViews. When scrolling in iOS5 (simulator and iphone) it works beautifully. But in iOS 4.3 (sim and phone) it kinda goes a bit crazy and scrolls passed more views than it should (about 10-15x more views than in iOS5). And to make it more strange it works as expected if I drag slowly so it doesn't continue scroll after I release.
The setup is kinda simple, I extend the UIScrollView class. And add UIView with a width of about 1500pt, in this I add my UIViews I want to scroll over. When scrolling the views are added and removed if they are off screen.
I think my problem lies with in this code:
- (void)recenterIfNecessary {
CGPoint currentOffset = [self contentOffset];
CGFloat contentWidth = [self contentSize].width;
CGFloat centerOffsetX = (contentWidth - [self bounds].size.width) / 2.0;
CGFloat distanceFromCenter = fabs(currentOffset.x - centerOffsetX);
UIView *image;
if (distanceFromCenter > (contentWidth / 4.0)) {
// Recenter the ScrollView so we never reach the edge
self.contentOffset = CGPointMake(centerOffsetX, currentOffset.y);
// Move visiblePhotos to new position to adjust to new contentOffset
for (image in visiblePhotos) {
CGPoint center = image.center;
center.x += (centerOffsetX - currentOffset.x);
image.center = center;
}
}
}
recenterIfNecessary is invoked here:
- (void)layoutSubviews {
[super layoutSubviews];
[self recenterIfNecessary];
[self tileImagesFromMinX:minVisibleX toMaxX:maxVisibleX];
//....
}
I've tried logging positions and offsets to try find a pattern with the difference between iOS4 & 5 with luck.
I got the concept and some code from http://developer.apple.com/videos/wwdc/2011/#advanced-scrollview-techniques (they use iOS5).
EDIT
Photos (that are put in the visiblePhotos array) are created with this methods:
- (CGFloat)placeNewImageOnRight:(CGFloat)rightEdge {
imageIndex = imageIndex < 0 ? ([reportItems count] - 1) : (imageIndex >= [reportItems count] ? 0 : imageIndex);
UIView *image = [self createItemContainer:[reportItems objectAtIndex:imageIndex]];
[visiblePhotos addObject:image];
CGRect frame = [image frame];
frame.origin.x = rightEdge;
frame.origin.y = [imageContainerView bounds].size.height - frame.size.height;
[image setFrame:frame];
imageIndex += 1;
return CGRectGetMaxX(frame);
}
- (CGFloat)placeNewImageOnLeft:(CGFloat)leftEdge {
imageIndex = imageIndex < 0 ? ([reportItems count] - 1) : (imageIndex >= [reportItems count] ? 0 : imageIndex);
UIView *image = [self createItemContainer:[reportItems objectAtIndex:imageIndex]];
[visiblePhotos insertObject:image atIndex:0];
CGRect frame = [image frame];
frame.origin.x = leftEdge - frame.size.width;
frame.origin.y = [imageContainerView bounds].size.height - frame.size.height;
[image setFrame:frame];
imageIndex -= 1;
return CGRectGetMinX(frame);
}
[self createItemContainer:[reportItems objectAtIndex:imageIndex]] creates a UIVeiw that contains a photo`.
The left and right methods are basically the same and are invoked by the method below. And tileImagesFromMinX is invoked on every frame by - (void)layoutSubviews.
- (void)tileImagesFromMinX:(CGFloat)minVisibleX toMaxX:(CGFloat)maxVisibleX {
if ([visiblePhotos count] == 0) {
[self placeNewImageOnRight:minVisibleX];
}
UIView *lastImage = [visiblePhotos lastObject];
CGFloat rightEdge = CGRectGetMaxX([lastImage frame]);
while (rightEdge < maxVisibleX) {
rightEdge = [self placeNewImageOnRight:rightEdge];
}
UIView *firstImage = [visiblePhotos objectAtIndex:0];
CGFloat leftEdge = CGRectGetMinX([firstImage frame]);
while (leftEdge > minVisibleX) {
leftEdge = [self placeNewImageOnLeft:leftEdge];
}
lastImage = [visiblePhotos lastObject];
while ([lastImage frame].origin.x > maxVisibleX) {
[lastImage removeFromSuperview];
[visiblePhotos removeLastObject];
lastImage = [visiblePhotos lastObject];
}
firstImage = [visiblePhotos objectAtIndex:0];
while (CGRectGetMaxX([firstImage frame]) < minVisibleX) {
[firstImage removeFromSuperview];
[visiblePhotos removeObjectAtIndex:0];
firstImage = [visiblePhotos objectAtIndex:0];
}
}
I've done a bunch of investigating and determined that you can't just set self.contentOffset = ...; and expect the scroll view to scroll/decelerate properly in iOS 4.3. So, even without the image tiling (and in fact you will notice this more clearly if you remove your images and just put a background on your image container view), your implementation of recenterIfNecessary will not work under 4.3 (this also affects the sample code on the developer site!).
Unfortunately, it seems the only way to work around this is to override -setContentOffset: and modify the offset there before calling super. Have a look at this question for some guidance on how to get that working correctly. I hope for your sake that this method will also work in iOS 5...
I'm trying to dynamically add Images to a ScrollView. Before adding I check if there are any subviews in the ScrollView and delete them in a for loop.
When I release the imageview I get a runtime error stating i'm trying to acces a deallocated instance. If I remove the release statement the application will run correctly but "build and analyze" shows a leak because th reference count of imageview is not decreased..
if ([scrollView.subviews count]>0){
for (int i=0; i<[scrollView.subviews count]; ++i) {
[[scrollView.subviews objectAtIndex:i] removeFromSuperview];
}
}
//Making a scroller with results
int scrollWidth = 0.0f;
int scrollHeight = 0.0f;
for (int i = 0; i<previewImages.count;++i)
{
UIImage *image=[previewImages objectAtIndex:i];
scrollWidth = scrollWidth + image.size.width; // Width of all the images
if (image.size.height > scrollHeight)scrollHeight= image.size.height; // Maximum image height
[image release];
}
float xC = 0.0f;
for (int i=0; i<previewImages.count; ++i) {
UIImage *image=[previewImages objectAtIndex:i];
UIImageView *imageview = [[UIImageView alloc] initWithFrame:CGRectMake(xC, 0.0f, image.size.width, image.size.height)];
UILabel *subScript = [[UILabel alloc] initWithFrame:CGRectMake(xC, image.size.height-30.0f, image.size.width,30.0f)];
subScript.textColor = [UIColor whiteColor];
subScript.backgroundColor = [UIColor colorWithWhite:0.5f alpha:0.5f];
subScript.text = [imagePaths objectAtIndex:i];
imageview.image = image;
xC = xC + image.size.width;
[image release];
[scrollView addSubview:imageview];
[imageview release];
[scrollView addSubview:subScript];
[subScript release];
}
[scrollView setContentSize:CGSizeMake(scrollWidth , scrollHeight)];
Any suggestions about the memory leak or general best practices for adding and removing views from an array into a scrollView are much appreciated!
if ([scrollView.subviews count]>0){
for (int i=0; i<[scrollView.subviews count]; ++i) {
[[scrollView.subviews objectAtIndex:i] removeFromSuperview];
}
}
is wrong, because you are removing subview from subviews array. Do reverse iteration would fix that, but I would suggest keeping the view in separated array instead.
I am trying to display about 53 images in Xcode for iphone, but about the 37th image crashes my entire app! If any one sees any errors in my code, I would really appreciate your help. Thank you!!
I think I am not releasing my images somewhere...just not sure what to do!
#import "MyProjectViewController.h"
#implementation MyProjectViewController
#synthesize scrollView1;
- (BOOL)shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation)interfaceOrientation {
return (interfaceOrientation == UIInterfaceOrientationLandscapeRight);
}
const CGFloat kScrollObjHeight = 320.0;
const CGFloat kScrollObjWidth = 480.0;
const NSUInteger kNumImages = 53;
- (void)layoutScrollImages
{
UIImageView *view = nil;
NSArray *subviews = [scrollView1 subviews];
CGFloat curXLoc = 0;
for (view in subviews)
{
if ([view isKindOfClass:[UIImageView class]] && view.tag > 0)
{
CGRect frame = view.frame;
frame.origin = CGPointMake(curXLoc, 0);
view.frame = frame;
curXLoc += (kScrollObjWidth);
}
}
[scrollView1 setContentSize:CGSizeMake((kNumImages * kScrollObjWidth), [scrollView1 bounds].size.height)];
}
- (void)viewDidLoad
{
self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor];
[scrollView1 setBackgroundColor:[UIColor blackColor]];
[scrollView1 setCanCancelContentTouches:NO];
scrollView1.indicatorStyle = UIScrollViewIndicatorStyleWhite;
scrollView1.clipsToBounds = YES;
scrollView1.scrollEnabled = YES;
scrollView1.pagingEnabled = YES;
NSUInteger i;
for (i = 1; i <= kNumImages; i++)
{
NSString *imageName = [NSString stringWithFormat:#"c1_%d.jpg", i];
UIImage *image = [UIImage imageNamed:imageName];
UIImageView *imageView = [[UIImageView alloc] initWithImage:image];
CGRect rect = imageView.frame;
rect.size.height = kScrollObjHeight;
rect.size.width = kScrollObjWidth;
imageView.frame = rect;
imageView.tag = i;
[scrollView1 addSubview:imageView];
[imageView release];
}
[self layoutScrollImages];
}
- (void)dealloc
{
[scrollView1 release];
[super dealloc];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
#end
Thank you!!!!!
How big are images? I suspect the problem is not with code itself, but with memory limitations of iPhone/iPod - if you're loading big images they simply eat all memory and program is closed.
Well the most likely reason is that you run out of memory. Put an NSLog message in didReceiveMemoryWarning to check if you are getting a warning for low memory.
In any case I would suggest that you lazy load images and not all of the images at once. It will greatly reduce to load time of your app and will also probably solve your memory problems. Use the UIScrollViewDelegate to know when to load images that weren't loaded yet according to the position of the UIScrollView offset value.