Praxder
Praxder

Reputation: 2779

Load "Loading" image before laoding Image from server?

I am new to iOS development so please bear with me. I am trying to create a basic photo gallery but ran into a problem. When I started out with the project I just included all the images in my project. Now after having a lot more images(400+) I started loading them from a server. I made an array of images using the following line of code:

[UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://www.testsite.com/testPic.png"]]]

Obviously making the user wait for an array of 400+ images to load from a server is unacceptable.

So my question is if I included one image in my project that said something like "Loading", how could I display that image until the actual image loaded from the server?

I'm making a basic grid-style photo gallery using a table-view and scroll-view. It loads up a few rows of small(thumbnail) images and when you click one it makes it full screen.

I'm using Xcode 4.3, ARC, and storyboards if that helps!

Sorry if this is confusing!

-Shredder2794

Upvotes: 0

Views: 1435

Answers (2)

Niko
Niko

Reputation: 2543

A method is to subclass UIImageView. When you allocate it you put a default image ( the loading one) or a UIActivityIndicator, download the image you want to display ( in a separate thread) and when the image is downloaded display it. Have a look to NSURLRequest and NSURLConnection for the image download.

* EDIT *

Here is an example of code I developed. You can use this as a start point to develop your own loading image class. This class can be improved by using NSThread for the image loading.

// ImageLoader.h


#import <UIKit/UIKit.h>
#import <Foundation/Foundation.h>

/**
 *  @brief  Class that loads an UIImage from a server
 *  @author Nicolas
 */
@interface ImageLoader : UIView 
{
    @private
    NSURLConnection         *connection;
    NSMutableData           *data;
    NSString                *path;
    UIActivityIndicatorView *loading;
    UIImageView             *imageView;
}

@property (nonatomic, retain) UIActivityIndicatorView   *loading;
@property (nonatomic, retain) NSURLConnection           *connection;
@property (nonatomic, retain) NSMutableData             *data;
@property (nonatomic, retain) NSString                  *path;
@property (nonatomic, retain) UIImageView               *imageView;

/**
 *  Load an image from a server an display it
 *  @param URL URL to get the image
 *  @param chemin path to save the image
 *  @author Nicolas
 */
- (void)loadImageFromUrl:(NSString *)URL forPath:(NSString *)chemin;

@end



// ImageLoader.m


#import "ImageLoader.h"


@implementation ImageLoader
@synthesize path, connection, data, loading, imageView;

- (id)init
{
    self = [super init];
    [self setUserInteractionEnabled:YES];
    return self;
}

- (void)loadImageFromUrl:(NSString *)URL forPath:(NSString *)chemin
{
    //if (connection != nil)    [connection release];
    //if (data !=  nil)     [data release];
    //if (path != nil)      [path release];

    self.path = chemin;

    if ([[NSFileManager defaultManager] fileExistsAtPath:chemin])
    {
        if (imageView != nil)
        {
            [imageView removeFromSuperview];
            [imageView release];
        }
        imageView = [[UIImageView alloc] initWithFrame:self.bounds];
        imageView.image = [UIImage imageWithContentsOfFile:chemin];
        [self addSubview:imageView];
    }
    else 
    {
        loading = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(0, 0, 20.0f, 20.0f)];
        loading.center = CGPointMake(self.frame.size.width/2, self.frame.size.height/2);
        [loading setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray];
        [loading startAnimating];
        [self addSubview:loading];

        NSURL *myURL = [NSURL URLWithString:[URL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];      
        NSURLRequest *request = [NSURLRequest requestWithURL:myURL cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30.0f];
        connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:YES];
    }
}

#pragma mark -
#pragma mark NSURLConnection protocol

- (void)connection:(NSURLConnection *)_connection didReceiveData:(NSData *)_data
{
    if (data == nil)
    {
        data = [[NSMutableData alloc] initWithCapacity:2048];
    }
    [data appendData:_data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)_connection
{
    [data writeToFile:self.path atomically:YES];

    if (imageView != nil)
    {
        [imageView removeFromSuperview];
        [imageView release];
    }

    imageView = [[UIImageView alloc] initWithImage:[UIImage imageWithData:data]];
    imageView.frame = self.bounds;
    imageView.contentMode = UIViewContentModeScaleAspectFit;
    imageView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
    [loading stopAnimating];
    [loading setHidden:YES];
    [self addSubview:imageView];
}

- (void)connection:(NSURLConnection *)_connection didFailWithError:(NSError *)error
{
    [loading stopAnimating];
    [loading release];
}

#pragma mark - Memory management

- (void)dealloc
{
    [connection cancel];
    [connection release];
    [imageView release];
    [path release];
    [data release];
    [super dealloc];
}

@end

Upvotes: 1

Jim
Jim

Reputation: 73966

The simplest way of doing this is to use AFNetworking, which provides setImageWithURL:placeholderImage: in a category on UIImageView (also a method with success/failure handlers).

Upvotes: 1

Related Questions