I know many of us have successfully done this.
I have tried to show the working via images. Hope it helps all the beginners like me to learn more.
Inside the View add a tableview and connect its DataSource and Delegate with the controller class.
You can also change the background color of the view to have a look like this :
Step - 3 : Now Open your LazyLoadingViewController.h file and write :
@interface LazyLoadingViewController : UIViewController<UITableViewDelegate,UITableViewDataSource>
{
IBOutlet UITableView *tableView;
NSArray *animals;
NSArray *animalUrl;
NSMutableDictionary *imageDict;
}
@property(nonatomic,retain)UITableView *tableView;
@property(nonatomic,retain)NSArray *animals;
@property(nonatomic,retain)NSArray *animalUrl;
@property(nonatomic,retain)NSMutableDictionary *imageDict;
-(NSString *) URLEncodeString:(NSString *) str;
@end
Step - 4 : Now Open your LazyLoadingViewController.m file and write this :
a) Synthesize all the properties that you created in .h class
b) Initialize your arrays and dictionary in ViewDidLoad.
I have done like this :
imageDict = [[NSMutableDictionary alloc] initWithCapacity:4];
animals = [NSArray arrayWithObjects:@"CAT",@"DOG",@"FOX",@"LION", nil];
animalUrl = [NSArray arrayWithObjects:
@"http://www.zastavki.com/pictures/1600x1200/2008/Animals_Cats_Small_cat_005241_.jpg",
@"http://spadogbotanicals.com/wp-content/uploads/puppy1-300x225.jpg",
@"http://www.nj.gov/dep/fgw/images/wildlife/fox_gl.jpg",
@"http://www.mikesel.info/wp-content/uploads/2011/07/lion.jpg",nil];
c) Now add all table view methods :
In our case the number of sections is only one but the rows depend on the total contents in the array we will use to display the contents in the table view
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [animals count];
}
d) For cell creation we want to display a default image in the image view till we get the image from server.In our case we have used this :
e) Cell creation is the most important part of the table view that will display the contents from the web when they are available. This is done via dispatching a background thread that fetches the images in background.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *Identifier=@"Identifier";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:Identifier];
if(cell == nil)
{
cell = [self reuseTableViewCellWithIdentifier:Identifier withIndexPath:indexPath];
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
//configure cell
UIImageView *imgView= (UIImageView *)[cell.contentView viewWithTag:IMG_TAG];
if([imageDict valueForKey:[NSString stringWithFormat:@"%i,%i", indexPath.row, indexPath.section]]==nil)
{
[NSThread detachNewThreadSelector:@selector(displayingSmallImage:)
toTarget:self withObject:indexPath];
}
else
{
imgView.image = [imageDict valueForKey:[NSString stringWithFormat:@"%i,%i",
indexPath.row, indexPath.section]];
}
UILabel *lblName = (UILabel *)[cell.contentView viewWithTag:TITLE_TAG];
[lblName setText:[animals objectAtIndex:indexPath.row]];
return cell;
}
-(UITableViewCell *)reuseTableViewCellWithIdentifier:(NSString *)identifier withIndexPath:(NSIndexPath *)indexPath
{
CGRect cellRectangle;
cellRectangle = CGRectMake(0.0, 0.0, 340, 180);
UITableViewCell *cell = [[UITableViewCell alloc]
initWithFrame:cellRectangle reuseIdentifier:identifier];
//here we create the image view and set its properties
UIImageView *img11;
cellRectangle = CGRectMake(15,18, 75, 70);
img11 = [[UIImageView alloc] initWithFrame:cellRectangle];
img11.tag = IMG_TAG;
img11.image = [UIImage imageNamed:@"base-image.png"] ;//acts as default image
img11.contentMode = UIViewContentModeScaleToFill;
[cell.contentView addSubview:img11];
//here we create the label and set its properties
UILabel *labelName;
cellRectangle = CGRectMake(150, 40, 200, 20);
labelName = [[UILabel alloc] initWithFrame:cellRectangle];
labelName.font =[UIFont fontWithName: @"Verdana"size:15.0f];
labelName.textColor = [UIColor blackColor];
labelName.autoresizingMask = UIViewAutoresizingFlexibleWidth;
labelName.tag = TITLE_TAG;
[cell.contentView addSubview:labelName];
return cell;
}
Note : Remember to add the labels and the image view to the cell's content view.
f) Encode URL : This is done to create verbatim string for url to override the behavior of the escape sequences.
-(NSString *) URLEncodeString:(NSString *) str
{
NSMutableString *tempStr = [NSMutableString stringWithString:str];
[tempStr replaceOccurrencesOfString:@" " withString:@"+" options:NSCaseInsensitiveSearch range:NSMakeRange(0, [tempStr length])];
return [[NSString stringWithFormat:@"%@",tempStr] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
}
g) Cell creation is the most important part of the table view that will display the contents from the web when they are available.If Image is available from the server we will display it else we will display the default image. You can see the test condition for this in BOLD.
After we get the image we save it in the dictionary and display the image on the image view in main thread i.e when the working of background thread is complete.
- (void) displayingSmallImage:(NSIndexPath *)indexPath
{
NSString *imageUrl = [animalUrl objectAtIndex:indexPath.row];
imageUrl = [self URLEncodeString:imageUrl];
NSURL *url = [NSURL URLWithString:imageUrl];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
if(image == nil)
{
image = [UIImage imageWithContentsOfFile:[[[NSBundle mainBundle]
resourcePath] stringByAppendingPathComponent:@"base-image.png"]];
}
[self.imageDict setObject:image forKey:[NSString
stringWithFormat:@"%i,%i",indexPath.row,indexPath.section]];
[self performSelectorOnMainThread:@selector(imageReceived:)
withObject:indexPath
waitUntilDone:NO];
}
h) Here we display the image received and reload the particular row of the table for which we got the image.
- (void) imageReceived:(NSIndexPath *)indexPath
{
UIImage *image = (UIImage *)[imageDict objectForKey:
[NSString stringWithFormat:@"%i,%i",
indexPath.row,indexPath.section]];
UIImageView *imgs = (UIImageView *)[[tableView
cellForRowAtIndexPath:indexPath] viewWithTag:IMG_TAG];
[imgs setImage:image];
[tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationNone];
}
i) Don't forget to add this tag in your .m file : This is done so that the labels and image views when created we assign a tag to them so that while giving them their values the same can be accessed via tags.
#define IMG_TAG 1
#define TITLE_TAG 2
This is to be done after the properties are synthesized.
j) You will see output like this :
i) When the Application is launched.
ii) When only 2 icons were fetched and rest are in transit
iii) When all icons were fetched from the web server
Enjoy table view and iOS....... :)