GCD on UITableView where NSURL is implemented - ios

i been trying to implement a GCD on my project which shows the fetch data from an XML, even though its my first time doing it i've succesfully(maybe) implemented in on nameLabel and detailLabel which are both string, but the imageLabel(commented part of the code) doesn't give anything when i try to implement the same GCD as both strings, i dont know whats happening but when i run the project it gives an unknown exception, i would like to know if how to implement a GCD on the commented part of the code so i will be able to show the image in the imageView.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"CustomCell";
dataFileHolder *currentData = [[xmlParser listPopulated] objectAtIndex:indexPath.row];
CustomCellXMLClass *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil) {
cell = [[CustomCellXMLClass alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCellXMLSample" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
myQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(myQueue, ^{
NSString *nameLabel = [currentData nameOfCat];
NSString *dataToCacheLabel = [myCache objectForKey:nameLabel];
if(nameLabel != nil){
dataToCacheLabel = [NSString stringWithString:nameLabel];
if (dataToCacheLabel != nil) {
[myCache setObject:dataToCacheLabel forKey:nameLabel];
dispatch_async(dispatch_get_main_queue(), ^{
[cell.nameLabel setText:dataToCacheLabel];
});
}
}
NSString *detailLabel = [currentData descriptionOfCat];
NSString *stringToCache = [myCache objectForKey:detailLabel];
if (detailLabel != nil) {
stringToCache = [NSString stringWithString:detailLabel];
if (stringToCache != nil) {
[myCache setObject:stringToCache forKey:detailLabel];
dispatch_async(dispatch_get_main_queue(), ^{
[cell.detailLabel setText:stringToCache];
});
}
}
// NSString *imageURL = [currentData imageLink];
// NSData *dataToCache;
// if (imageURL != nil) {
//
// dataToCache = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageURL]];
// if (dataToCache != nil) {
//
// [myCache setObject:dataToCache forKey:imageURL];
// [cell.imageShow setImage:[UIImage imageWithData:dataToCache]];
//
// }
// else {
//
// NSURL *imageURL = [NSURL URLWithString:#"http://i178.photobucket.com/albums/w255/ace003_album/190579604m.jpg"];
// dataToCache = [NSData dataWithContentsOfURL:imageURL];
// [myCache setObject:dataToCache forKey:imageURL];
// [cell.imageShow setImage:[UIImage imageWithData:dataToCache]];
// }
//
// }
[self.activityIndicator performSelectorOnMainThread:#selector(stopAnimating) withObject:nil waitUntilDone:YES];
});
return cell;
}

You need to dispatch the parts where you update the cell back to the main thread like you are doing for the first two. This part: dispatch_async(dispatch_get_main_queue(),...) It'll probably look something like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"CustomCell";
static NSInteger usageCount = 0;
dataFileHolder *currentData = [[xmlParser listPopulated] objectAtIndex:indexPath.row];
CustomCellXMLClass *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil) {
cell = [[CustomCellXMLClass alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCellXMLSample" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
// Give it a new tag every time, so we can tell if this is "our" use of the cell
cell.tag = ++usageCount;
myQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(myQueue, ^{
NSString *nameLabel = [currentData nameOfCat];
NSString *dataToCacheLabel = [myCache objectForKey:nameLabel];
if(nameLabel != nil){
dataToCacheLabel = [NSString stringWithString:nameLabel];
if (dataToCacheLabel != nil) {
[myCache setObject:dataToCacheLabel forKey:nameLabel];
dispatch_async(dispatch_get_main_queue(), ^{
if (cell.superview && usageCount == cell.tag)
{
[cell.nameLabel setText:dataToCacheLabel];
}
});
}
}
NSString *detailLabel = [currentData descriptionOfCat];
NSString *stringToCache = [myCache objectForKey:detailLabel];
if (detailLabel != nil) {
stringToCache = [NSString stringWithString:detailLabel];
if (stringToCache != nil) {
[myCache setObject:stringToCache forKey:detailLabel];
dispatch_async(dispatch_get_main_queue(), ^{
if (cell.superview && usageCount == cell.tag)
{
[cell.detailLabel setText:stringToCache];
}
});
}
}
NSURL *fallbackImageURL = [NSURL URLWithString:#"http://i178.photobucket.com/albums/w255/ace003_album/190579604m.jpg"];
NSString *imageURL = [currentData imageLink];
NSArray* urls = imageURL ? #[ imageURL, fallbackImageURL ] : #[ fallbackImageURL ];
for (NSURL* url in urls)
{
UIImage* cachedImage = [myCache objectForKey: url];
if (!cachedImage)
{
NSData* imageData = [NSData dataWithContentsOfURL:url];
cachedImage = [UIImage imageWithData:dataToCache];
[myCache setObject:cachedImage forKey:url];
}
if (cachedImage)
{
dispatch_async(dispatch_get_main_queue(), ^{
if (cell.superview && usageCount == cell.tag)
{
[cell.imageShow setImage: uiImage];
}
});
break;
}
}
});
return cell;
}
In the long term, you should probably also consider any of a number of asynchronous loading approaches instead of dataWithContentsOfURL: which will block the background thread waiting for the data to be fully received. But that's a second-order issue here, and not what you asked about.
EDIT: Edited for #Rob's comments. Check the cache for a pre-cached image before fetching, and guard against writing values into reused or invisible cells (assuming you're not using tag for something else.) But really, just use an asynchronous image download manager.

Related

How to improve load image in UITableview?

I have a problem when i load imageview in table view. It's Loading so slowly. I use a lot of section in my table view. There is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
TrangChuTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CellTrangchu" forIndexPath:indexPath];
theGame *thegameObj;
if([indexPath section] == 0){
thegameObj = [theZingArray objectAtIndex:indexPath.row];
}else if([indexPath section] == 1){
thegameObj = [theBitArray objectAtIndex:indexPath.row];
}else if([indexPath section] == 2){
thegameObj = [theMobayArray objectAtIndex:indexPath.row];
}else if([indexPath section] == 3){
thegameObj = [theGateArray objectAtIndex:indexPath.row];
}else if([indexPath section] == 4){
thegameObj = [theVcoinArray objectAtIndex:indexPath.row];
}else if([indexPath section] == 5){
thegameObj = [theGarenaArray objectAtIndex:indexPath.row];
}else if([indexPath section] == 6){
thegameObj = [theOncashArray objectAtIndex:indexPath.row];
}else if([indexPath section] == 7){
thegameObj = [theMobiphoneArray objectAtIndex:indexPath.row];
}else if([indexPath section] == 8){
thegameObj = [theVinaphoneArray objectAtIndex:indexPath.row];
}else if([indexPath section] == 9){
thegameObj = [theViettelArray objectAtIndex:indexPath.row];
}
NSURL *urlImage = [NSURL URLWithString:thegameObj.image];
NSData *imageData = [NSData dataWithContentsOfURL:urlImage];
cell.txtQuantity.text=#"1";
UIImage *image= [UIImage imageWithData:imageData];
cell.imageView.layer.cornerRadius=5;
cell.imageView.layer.masksToBounds=YES;
cell.imageView.image = image;
cell.labelName.text = thegameObj.objectName;
if([[AppDelegate appDelegate]checkIP])
{
[cell.txtQuantity setBackgroundColor:[UIColor whiteColor]];
[cell.txtQuantity.layer setBorderColor:[UIColor grayColor].CGColor];
[cell.txtQuantity.layer setBorderWidth:1.0];
[cell.txtQuantity.layer setCornerRadius:5];
cell.labelPrice.text = [NSString stringWithFormat:#"%# (%#)", [NSNumberFormatter localizedStringFromNumber:thegameObj.price numberStyle:NSNumberFormatterDecimalStyle], loadCurrency];
}
else
{
[cell.lbdetail setTitle:#"detail" forState:UIControlStateNormal];
cell.txtQuantity.hidden=YES;
cell.labelPrice.hidden=YES;
cell.lbgia.hidden=YES;
cell.lbsl.hidden=YES;
cell.lbdetail.hidden=YES;
}
cell.objArray = thegameObj;
cell.currency = loadCurrency;
/*
[cell.addToCartButton addTarget:self action:#selector(addToCart:) forControlEvents:UIControlEventTouchUpInside];
cell.addToCartButton.tag = [NSString stringWithFormat:#"%d_%d", (NSInteger)[indexPath section], (NSInteger)[indexPath row]];
*/
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
return cell;
}
Please help me improve more faster load image with alot of section in UItableview. Thank you for any solution!
One thing that will help is a data structure that matches a sectioned table model, which is an array of arrays. You're almost there, since you have all of the sub-arrays. Build one like this (when all the sub-arrays are built, not in cellForRow):
NSArray *model = #[ theZingArray, theBitArray, /*... and so on */];
That will let you flatten the big conditional to one line:
thegameObj = model[indexPath.section][indexPath.row];
You can use that elsewhere, like in numberRowsInSection
NSArray *sectionArray = model[indexPath.section];
return sectionArray.count;
The slightly tougher problem is to have those images load async and get cached. A fully native approach is discussed here and many others.
Applying this idea to your code, here's a method that returns either a cached image, or fetches, caches and returns...
// declare this and BE SURE TO INITIALIZE IT
#property(strong,nonatomic) NSMutableDictionary *imageCache;
// return an image found at the url string, if one is cached return it, otherwise,
// fetch it, cache it and return it
- (void)imageAtURLString:(NSString *)urlString completion:(void(^)(UIImage *, BOOL))completion {
if (self.imageCache[urlString]) { // if it's cached
completion(self.imageCache[urlString], YES);
} else { // fetch and cahce
NSURL *url = [NSURL URLWithString:urlString];
NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (data) {
UIImage *image = [UIImage imageWithData:data];
if (image) {
self.imageCache[urlString] = image;
dispatch_async(dispatch_get_main_queue(), ^{
completion(image, NO);
});
}
}
}];
[task resume];
}
}
Now your simplified cellForRowAtIndexPath can look like this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cellid"]; // fixme
theGame *thegameObj = model[indexPath.section][indexPath.row];
NSString *urlString = thegameObj.image;
UIImageView *imageView = cell.imageView;
[self imageAtURLString:urlString completion:^(UIImage *image, BOOL wasCached) {
if (wasCached) imageView.image = image;
else [tableView reloadRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}];
return cell;
}
The idea here is that you either have a cached image, in which case, just set the cell's imageView image to that, or you had to fetch one. In the case of the fetch, it's uncertain whether the row got scrolled away during the fetch. Reload the current row to cause it to update with the (now cached) image.
There is concept of image caching with which image view loads images asynchronously in background. Refer following link
https://github.com/nicklockwood/AsyncImageView
Use following awesome library for download image in background.
https://github.com/rs/SDWebImage
UIImageView * thumbnail = [[UIImageView alloc] init];
NSURL *urlToPicture1 = [NSURL URLWithString:currentMarker.thumbnail];
[thumbnail sd_setImageWithURL:urlToPicture1 placeholderImage:[UIImage imageNamed:#"placeholder.png"] options:SDWebImageProgressiveDownload completed:^(UIImage * image, NSError * error,SDImageCacheType cachedType, NSURL * imageURL){
if(image){
[thumbnail setImage:image];
NSLog(#"Complete = %d, error = %#",cachedType, error);
}
}];

How to set image path coming from server in uitableviewcell

I am making an app in which i am getting data from server and in data image path is also coming but when i am setting image to my tableview cell app will become too much heavy may b i am not setting image properly below is my sample code thanx in advance :)
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *tableviewidentifier = #"cell";
tablecellTableViewCell *cell= [self.activitiesTableView_ dequeueReusableCellWithIdentifier:tableviewidentifier];
if(cell==nil)
{
cell = [[tablecellTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:tableviewidentifier];
}if(indexPath.row == [self tableView:tableView numberOfRowsInSection:indexPath.section] - 1){
// [[cell textLabel] setText:#"Load more records"];
}
UILabel *valuedate = (UILabel *)[cell viewWithTag:21];
UILabel *msg = (UILabel *)[cell viewWithTag:22];
UILabel *date = (UILabel *)[cell viewWithTag:23];
UILabel *time = (UILabel *)[cell viewWithTag:24];
valuedate.text=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"offerTitle"];
msg.text=#"How are you?";
NSString *img=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"offerPhoto"];// here i am getting image path
UIImage *img1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:img]]];
cell.imageView.image=img1;// here i am setting image due to which app is so heavy and stuck
return cell;
}
Dont use imageWithData: for setting images. It is synchronous and will make your app run slow.
Instead of that Use SDWebImage
You just need to do following things:
Dump SDWebImage folder into your project.
Import UIImageView+WebCache.h.
Set the image using: sd_setImageWithURL:
OR
by GCD (Grand Central Dispatch) and sending asynchronous requests. Code copied from HERE.
First implement following method.
- (void)downloadImageWithURL:(NSURL *)url completionBlock:(void (^)(BOOL succeeded, UIImage *image))completionBlock
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if ( !error )
{
UIImage *image = [[UIImage alloc] initWithData:data];
completionBlock(YES,image);
} else{
completionBlock(NO,nil);
}
}];
}
and then in your cellForRowAtIndexPath
[self downloadImageWithURL:your_url completionBlock:^(BOOL succeeded, UIImage *image) {
if (succeeded) {
// change the image in the cell
cell.imageView.image = image;
}
}];
try this below code, hope this helps u .
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
__block tablecellTableViewCell *cell= [self.activitiesTableView_ dequeueReusableCellWithIdentifier:tableviewidentifier];
if(cell==nil)
{
cell = [[tablecellTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:tableviewidentifier];
}
if(indexPath.row == [self tableView:tableView numberOfRowsInSection:indexPath.section] - 1)
{
// [[cell textLabel] setText:#"Load more records"];
}
UILabel *valuedate = (UILabel *)[cell viewWithTag:21];
UILabel *msg = (UILabel *)[cell viewWithTag:22];
UILabel *date = (UILabel *)[cell viewWithTag:23];
UILabel *time = (UILabel *)[cell viewWithTag:24];
valuedate.text=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"offerTitle"];
msg.text=#"How are you?";
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSString *img=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"offerPhoto"];// here i am getting image path
NSURL *url = [NSURL URLWithString:img];
NSData * imageData = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageData];
dispatch_sync(dispatch_get_main_queue(), ^{ //in main thread update the image
cell.imageView.image = image;
cell.textLabel.text = #""; //add this update will reflect the changes
});
});
return cell;
}
EDIT
in order to reuse the downloaded image u can either save them on disk or just for save them some where for example in dictionary for temporary using
in below code i took one example dictionary, and strong the download images with row as key
#interface ViewController ()
{
NSMutableDictionary *imagesDictionary; //lets declare a mutable dictionary to hold images
}
in this method just initialise it
- (void)viewDidLoad {
[super viewDidLoad];
// rest of your code
//...........
//
imagesDictionary = [[NSMutableDictionary alloc]init]; //initilise
}
in index this method just add the downloaded images to dictionary for corresponding row as key
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
__block tablecellTableViewCell *cell= [self.activitiesTableView_ dequeueReusableCellWithIdentifier:tableviewidentifier];
if(cell==nil)
{
cell = [[tablecellTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:tableviewidentifier];
}
if(indexPath.row == [self tableView:tableView numberOfRowsInSection:indexPath.section] - 1)
{
// [[cell textLabel] setText:#"Load more records"];
}
__block NSString *row = [NSString stringWithFormat:#"%d",indexPath.row]; //add this
UILabel *valuedate = (UILabel *)[cell viewWithTag:21];
UILabel *msg = (UILabel *)[cell viewWithTag:22];
UILabel *date = (UILabel *)[cell viewWithTag:23];
UILabel *time = (UILabel *)[cell viewWithTag:24];
// valuedate.text=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"offerTitle"];
msg.text=#"How are you?";
if(![[imagesDictionary allKeys] containsObject:row]) //if image not found download and add it to dictionary
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
// NSString *img=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"offerPhoto"];// here i am getting image path
NSURL *url = [NSURL URLWithString:img];
NSData * imageData = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageData];
dispatch_sync(dispatch_get_main_queue(), ^{ //in main thread update the image
[imagesDictionary setObject:image forKey:row]; //sorry, while editing to your code i forgot to add this
cell.imageView.image = image;
cell.textLabel.text = #""; //add this update will reflect the changes
NSLog(#"loading and addig to dictionary");
});
});
}
else
{
cell.imageView.image = [imagesDictionary objectForKey:row];
NSLog(#"retriving from dictioary");
}
return cell;
}
First of all you are calling dataWithContentsOfURL: function which will make the app non responsive because you are calling it on main thread. To make it responsive you need to create a custom cell YourCell and declare a method in YourCell.h
#interface YourCell : UITableViewCell
{
UIImage *_cImage;
}
- (void)downloadImageFromURL:(NSURL *)imageUrl;
#end
Now in YourCell.m you need to do like this:
- (void)downloadImageFromURL:(NSURL *)imageUrl
{
if (_cImage != nil)
{
self.imageView.image = _cImage;
}
else
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
_cImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageUrl]];
dispatch_sync(dispatch_get_main_queue(), ^{
self.imageView.image = _cImage;
});
});
}
}
Now from cellForRowAtIndexPath: you just need to call downloadImageFromURL: function of YourCell and pass the imageUrl to it and its the cell responsibility to download and show the image.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier= #"YourCell";
YourCell *cell = (YourCell *)[self.activitiesTableView_ dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[NSBundle mainBundle] loadNibNamed:#"YourCell" owner:self options:nil] objectAtIndex:0];
}
// Set your UILabels as before.....
NSString *imagePath=[[self.inboxmessagesarray objectAtIndex:indexPath.row] objectForKey:#"offerPhoto"];
[cell downloadImageFromURL:[NSURL URLWithString:imagePath]];
return cell;
}
Let me know if you have any questions.
UIImageView *img1 = (UIImageView *)[cell viewWithTag:104];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
img1.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:img]]];
});
});
Send async requests for images. Doing this would not block your UI until the image gets loaded.

ios tableview image load duplicate when scrolling tableview

I make two custom cell and display in single UITableView in odd even orders, but when i scroll UITableView all image and schedule data color will change randomly and duplicate data will displayed but name,exp., pri-zone, and rate which is in string they all display proper,only image and color of schedule text will change.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
if (indexPath.row % 2 == 0) {
static NSString *cellIdentifier=#"MyCustomCell";
TableViewCell *cell=[tblResponseData dequeueReusableCellWithIdentifier:cellIdentifier];
if (cell == nil)
{
cell = [[TableViewCell alloc] initWithStyle:UITableViewCellStyleValue1
reuseIdentifier:cellIdentifier];
}
NSString *imgPath=[[arrData objectAtIndex:indexPath.row]valueForKey:#"Pic"];
// NSString *imgPath=[[appDelegate.arrData
objectAtIndex:indexPath.row]valueForKey:#"image"];
NSURL *url = [NSURL URLWithString:[imgPath
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSString *schedule =[[arrData objectAtIndex:indexPath.row]valueForKey:#"Schedule"];
NSArray *strings = [schedule componentsSeparatedByString:#","];
//NSURL *url = [NSURL URLWithString:url];
[NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:url]
queue:[NSOperationQueue currentQueue]
completionHandler:^(NSURLResponse * resp, NSData * data, NSError
* error)
{
if(error == NULL){
// here is our image
UIImage *image = [UIImage imageWithData:data];
cell.imgThumbnail.image=image;
}
else{
cell.imgThumbnail.image=[UIImage imageNamed:#"no preview 2.jpeg"];
}
}];
for (NSString *item in strings)
{
if ([item isEqualToString:#"Su"]) {
cell.lblsu.textColor = [UIColor greenColor];
}else if ([item isEqualToString:#"Tu"]){
cell.lblt.textColor = [UIColor greenColor];
}else if ([item isEqualToString:#"Th"]){
cell.lblth.textColor = [UIColor greenColor];
}
else if ([item isEqualToString:#"M"]){
cell.lblm.textColor = [UIColor greenColor];
}
else if ([item isEqualToString:#"F"]){
cell.lblf.textColor = [UIColor greenColor];
}
else if ([item isEqualToString:#"S"]){
cell.lbls.textColor = [UIColor greenColor];
}
else if ([item isEqualToString:#"W"]){
cell.lblw.textColor = [UIColor greenColor];
}
}
cell.lblname.text = [[arrData objectAtIndex:indexPath.row] valueForKey:#"Worker Name"];
cell.lblexperience.text=[[arrData o
bjectAtIndex:indexPath.row]valueForKey:#"Experience"];
cell.lblprizone.text=[[arrData objectAtIndex:indexPath.row]valueForKey:#"Primary
Zone"];
cell.lblrate.text=[[arrData objectAtIndex:indexPath.row]valueForKey:#"Rate"];
return cell;
} else {
static NSString *cellIdentifier1=#"MyCustomCell1";
TableViewCell *cell1=[tblResponseData d
equeueReusableCellWithIdentifier:cellIdentifier1];
if (cell1 == nil)
{
cell1 = [[TableViewCell alloc] initWithStyle:UITableViewCellStyleValue1
reuseIdentifier:cellIdentifier1];
}
NSString *imgPath=[[arrData objectAtIndex:indexPath.row]valueForKey:#"Pic"];
// NSString *imgPath=[[appDelegate.arrData
objectAtIndex:indexPath.row]valueForKey:#"image"];
NSURL *url = [NSURL URLWithString:[imgPath
stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
//NSURL *url = [NSURL URLWithString:url];
[NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:url]
queue:[NSOperationQueue currentQueue]
completionHandler:^(NSURLResponse * resp, NSData * data, NSError
* error)
{
if(error == NULL){
// here is our image
UIImage *image = [UIImage imageWithData:data];
cell1.imgThumbnail.image=image;
}
else{
cell1.imgThumbnail.image=[UIImage imageNamed:#"no preview 2.jpeg"];
}
}];
// NSURL *imageUrl = [NSURL URLWithString:imgPath];
// NSData *imageData = [NSData dataWithContentsOfURL:url];
// UIImage *image=[[UIImage alloc]initWithData:imageData];
// cell.imgThumbnail.image=image;
NSString *schedule =[[arrData objectAtIndex:indexPath.row]valueForKey:#"Schedule"];
NSArray *strings = [schedule componentsSeparatedByString:#","];
for (NSString *item in strings)
{
if ([item isEqualToString:#"Su"]) {
cell1.lblsu.textColor = [UIColor greenColor];
}else if ([item isEqualToString:#"Tu"]){
cell1.lblt.textColor = [UIColor greenColor];
}else if ([item isEqualToString:#"Th"]){
cell1.lblth.textColor = [UIColor greenColor];
}
else if ([item isEqualToString:#"M"]){
cell1.lblm.textColor = [UIColor greenColor];
}
else if ([item isEqualToString:#"F"]){
cell1.lblf.textColor = [UIColor greenColor];
}
else if ([item isEqualToString:#"S"]){
cell1.lbls.textColor = [UIColor greenColor];
}
else if ([item isEqualToString:#"W"]){
cell1.lblw.textColor = [UIColor greenColor];
}
}
cell1.lblname.text = [[arrData objectAtIndex:indexPath.row] valueForKey:#"Worker N
ame"];
cell1.lblexperience.text=[[arrData
objectAtIndex:indexPath.row]valueForKey:#"Experience"];
cell1.lblprizone.text=[[arrData objectAtIndex:indexPath.row]valueForKey:#"Primary
Zone"];
cell1.lblrate.text=[[arrData objectAtIndex:indexPath.row]valueForKey:#"Rate"];
return cell1;
}
}
I think it might be because you load your images by NSURLConnection sendAsynchronousRequest. Because the completitionhandler isn't called immediately, but when the data is returned to the request. So the images will be set after the cells are loaded.
Try to replace
[NSURLConnection sendAsynchronousRequest:[NSURLRequest requestWithURL:url]
queue:[NSOperationQueue currentQueue]
completionHandler:^(NSURLResponse * resp, NSData * data, NSError
* error)
{
if(error == NULL){
// here is our image
UIImage *image = [UIImage imageWithData:data];
cell1.imgThumbnail.image=image;
}
else{
cell1.imgThumbnail.image=[UIImage imageNamed:#"no preview 2.jpeg"];
}
}];
with code that will set imgThumbnail.image to an image that is in your project and see whether you still get radomly changing cells.
Problem: You are using dequeueReusableCellWithIdentifier so the same cell is reused when you are scrolling the tableview and you are send a AsynchronousRequest in that cell so the previously sent cell response we are receiving on another cell so it is showing different result.
For example: Cell 2 you are sending a request and then you scrolled the table view so the same cell is reused for cell 10 by that time you will receive the response of cell 2 send request and that image (response data) is displayed in cell 10.
Solution: send the request in separate method and save the images in array or dictionary then reload the corresponding cells based on the the received response.
For Example:EGOImageView is sending request asynchronously and saving in cache and displaying after receiving response please check that once
try this one ,for loading the images From webservices.
NSString *imgUrl = [[arrCategoryDetails objectAtIndex:indexPath.row]valueForKey:#"Image"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:imgUrl]];
if (imgData) {
UIImage *image = [UIImage imageWithData:imgData];
if (image) {
dispatch_async(dispatch_get_main_queue(), ^{
CategoryDetailsTableCell *updateCell = (id)[tableView cellForRowAtIndexPath:indexPath];
if (updateCell)
updateCell.imgForCategoryDetailCell.image = image;
});
}
}
});

showing UIActivityIndicator on fetch of XML

what im trying to do is parse an XML data and show it in my UITableView but the thing is it shows like after 2-3 seconds, im trying to include a UIActivityIndicator when the data loads and also im trying to include a gcd, but the thing is im new at this stuff so im really confuse on what to do or where do i posible put the gcd code.
that is my .m file.
#implementation ViewController
#synthesize listTableView;
dispatch_queue_t myQueue;
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [[xmlParser listPopulated]count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"CustomCell";
dataFileHolder *currentData = [[xmlParser listPopulated] objectAtIndex:indexPath.row];
CustomCellXMLClass *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil) {
cell = [[CustomCellXMLClass alloc]initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCellXMLSample" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
NSString *nameLabel = [currentData nameOfCat];
NSString *dataToCacheLabel = [myCache objectForKey:nameLabel];
if(nameLabel != nil){
dataToCacheLabel = [NSString stringWithString:nameLabel];
if (dataToCacheLabel != nil) {
[myCache setObject:dataToCacheLabel forKey:nameLabel];
[cell.nameLabel setText:dataToCacheLabel];
}
}
NSString *detailLabel = [currentData descriptionOfCat];
NSString *stringToCache = [myCache objectForKey:detailLabel];
if (detailLabel != nil) {
stringToCache = [NSString stringWithString:detailLabel];
if (stringToCache != nil) {
[myCache setObject:stringToCache forKey:detailLabel];
[cell.detailLabel setText:stringToCache];
}
}
NSString *imageURL = [currentData imageLink];
NSData *dataToCache;
if (imageURL != nil) {
dataToCache = [NSData dataWithContentsOfURL:[NSURL URLWithString:imageURL]];
if (dataToCache != nil) {
[myCache setObject:dataToCache forKey:imageURL];
[cell.imageShow setImage:[UIImage imageWithData:dataToCache]];
}
else {
NSURL *imageURL = [NSURL URLWithString:#"http://i178.photobucket.com/albums/w255/ace003_album/190579604m.jpg"];
dataToCache = [NSData dataWithContentsOfURL:imageURL];
[myCache setObject:dataToCache forKey:imageURL];
[cell.imageShow setImage:[UIImage imageWithData:dataToCache]];
}
}
return cell;
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
return 78;
}
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section{
NSString *title = #"Sample View";
return title;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self.activityIndicator startAnimating];
self.activityIndicator.hidesWhenStopped = YES;
dispatch_queue_t myQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(myQueue, ^ {
xmlParser = [[XMLParser alloc]loadXMLByURL:#"http://www.irabwah.com/mobile/core.php?cat=0"];
[self.activityIndicator performSelectorOnMainThread:#selector(stopAnimating) withObject:nil waitUntilDone:YES];
});
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#end
Depending on how XMLParser works your current CGD block is ok for that. You wouldn't usually use performSelectorOnMainThread to return the UI interaction to the main thread but that's just a common convention thing.
Most of your problem could be coming from dataWithContentsOfURL: which you're calling on the main thread in cellForRowAtIndexPath:. You might want to take a look at SDWebImage to help with that, but you could do it yourself with GCD too.
cellForRowAtIndexPath will not be called just because your XML finished loading. In your code block, I suggest before calling stopAnimating that you call reloadData on your UITableView; this will trigger a series of calls, first to numberOfRowsInSection and then to cellForRowAtIndexPath repeatedly. Try putting breakpoints in these functions so you can see the flow of execution.

Async image loading from url inside a UITableView cell - image changes to wrong image while scrolling

I've written two ways to async load pictures inside my UITableView cell. In both cases the image will load fine but when I'll scroll the table the images will change a few times until the scroll will end and the image will go back to the right image. I have no idea why this is happening.
#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
- (void)viewDidLoad
{
[super viewDidLoad];
dispatch_async(kBgQueue, ^{
NSData* data = [NSData dataWithContentsOfURL: [NSURL URLWithString:
#"http://myurl.com/getMovies.php"]];
[self performSelectorOnMainThread:#selector(fetchedData:)
withObject:data waitUntilDone:YES];
});
}
-(void)fetchedData:(NSData *)data
{
NSError* error;
myJson = [NSJSONSerialization
JSONObjectWithData:data
options:kNilOptions
error:&error];
[_myTableView reloadData];
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
// Return the number of rows in the section.
// Usually the number of items in your array (the one that holds your list)
NSLog(#"myJson count: %d",[myJson count]);
return [myJson count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
myCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (cell == nil) {
cell = [[myCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
dispatch_async(kBgQueue, ^{
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[NSString stringWithFormat:#"http://myurl.com/%#.jpg",[[myJson objectAtIndex:indexPath.row] objectForKey:#"movieId"]]]];
dispatch_async(dispatch_get_main_queue(), ^{
cell.poster.image = [UIImage imageWithData:imgData];
});
});
return cell;
}
...
...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
myCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell"];
if (cell == nil) {
cell = [[myCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"cell"];
}
NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:#"http://myurl.com/%#.jpg",[[myJson objectAtIndex:indexPath.row] objectForKey:#"movieId"]]];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * data,
NSError * error) {
if (!error){
cell.poster.image = [UIImage imageWithData:data];
// do whatever you want with image
}
}];
return cell;
}
Assuming you're looking for a quick tactical fix, what you need to do is make sure the cell image is initialized and also that the cell's row is still visible, e.g:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
cell.poster.image = nil; // or cell.poster.image = [UIImage imageNamed:#"placeholder.png"];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://myurl.com/%#.jpg", self.myJson[indexPath.row][#"movieId"]]];
NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (data) {
UIImage *image = [UIImage imageWithData:data];
if (image) {
dispatch_async(dispatch_get_main_queue(), ^{
MyCell *updateCell = (id)[tableView cellForRowAtIndexPath:indexPath];
if (updateCell)
updateCell.poster.image = image;
});
}
}
}];
[task resume];
return cell;
}
The above code addresses a few problems stemming from the fact that the cell is reused:
You're not initializing the cell image before initiating the background request (meaning that the last image for the dequeued cell will still be visible while the new image is downloading). Make sure to nil the image property of any image views or else you'll see the flickering of images.
A more subtle issue is that on a really slow network, your asynchronous request might not finish before the cell scrolls off the screen. You can use the UITableView method cellForRowAtIndexPath: (not to be confused with the similarly named UITableViewDataSource method tableView:cellForRowAtIndexPath:) to see if the cell for that row is still visible. This method will return nil if the cell is not visible.
The issue is that the cell has scrolled off by the time your async method has completed, and, worse, the cell has been reused for another row of the table. By checking to see if the row is still visible, you'll ensure that you don't accidentally update the image with the image for a row that has since scrolled off the screen.
Somewhat unrelated to the question at hand, I still felt compelled to update this to leverage modern conventions and API, notably:
Use NSURLSession rather than dispatching -[NSData contentsOfURL:] to a background queue;
Use dequeueReusableCellWithIdentifier:forIndexPath: rather than dequeueReusableCellWithIdentifier: (but make sure to use cell prototype or register class or NIB for that identifier); and
I used a class name that conforms to Cocoa naming conventions (i.e. start with the uppercase letter).
Even with these corrections, there are issues:
The above code is not caching the downloaded images. That means that if you scroll an image off screen and back on screen, the app may try to retrieve the image again. Perhaps you'll be lucky enough that your server response headers will permit the fairly transparent caching offered by NSURLSession and NSURLCache, but if not, you'll be making unnecessary server requests and offering a much slower UX.
We're not canceling requests for cells that scroll off screen. Thus, if you rapidly scroll to the 100th row, the image for that row could be backlogged behind requests for the previous 99 rows that aren't even visible anymore. You always want to make sure you prioritize requests for visible cells for the best UX.
The simplest fix that addresses these issues is to use a UIImageView category, such as is provided with SDWebImage or AFNetworking. If you want, you can write your own code to deal with the above issues, but it's a lot of work, and the above UIImageView categories have already done this for you.
/* I have done it this way, and also tested it */
Step 1 = Register custom cell class (in case of prototype cell in table) or nib (in case of custom nib for custom cell) for table like this in viewDidLoad method:
[self.yourTableView registerClass:[CustomTableViewCell class] forCellReuseIdentifier:#"CustomCell"];
OR
[self.yourTableView registerNib:[UINib nibWithNibName:#"CustomTableViewCell" bundle:nil] forCellReuseIdentifier:#"CustomCell"];
Step 2 = Use UITableView's "dequeueReusableCellWithIdentifier: forIndexPath:" method like this (for this, you must register class or nib) :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CustomTableViewCell * cell = [tableView dequeueReusableCellWithIdentifier:#"CustomCell" forIndexPath:indexPath];
cell.imageViewCustom.image = nil; // [UIImage imageNamed:#"default.png"];
cell.textLabelCustom.text = #"Hello";
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// retrive image on global queue
UIImage * img = [UIImage imageWithData:[NSData dataWithContentsOfURL: [NSURL URLWithString:kImgLink]]];
dispatch_async(dispatch_get_main_queue(), ^{
CustomTableViewCell * cell = (CustomTableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
// assign cell image on main thread
cell.imageViewCustom.image = img;
});
});
return cell;
}
There are multiple frameworks that solve this problem. Just to name a few:
Swift:
Nuke (mine)
Kingfisher
AlamofireImage
HanekeSwift
Objective-C:
AFNetworking
PINRemoteImage
YYWebImage
SDWebImage
Swift 3
I write my own light implementation for image loader with using NSCache.
No cell image flickering!
ImageCacheLoader.swift
typealias ImageCacheLoaderCompletionHandler = ((UIImage) -> ())
class ImageCacheLoader {
var task: URLSessionDownloadTask!
var session: URLSession!
var cache: NSCache<NSString, UIImage>!
init() {
session = URLSession.shared
task = URLSessionDownloadTask()
self.cache = NSCache()
}
func obtainImageWithPath(imagePath: String, completionHandler: #escaping ImageCacheLoaderCompletionHandler) {
if let image = self.cache.object(forKey: imagePath as NSString) {
DispatchQueue.main.async {
completionHandler(image)
}
} else {
/* You need placeholder image in your assets,
if you want to display a placeholder to user */
let placeholder = #imageLiteral(resourceName: "placeholder")
DispatchQueue.main.async {
completionHandler(placeholder)
}
let url: URL! = URL(string: imagePath)
task = session.downloadTask(with: url, completionHandler: { (location, response, error) in
if let data = try? Data(contentsOf: url) {
let img: UIImage! = UIImage(data: data)
self.cache.setObject(img, forKey: imagePath as NSString)
DispatchQueue.main.async {
completionHandler(img)
}
}
})
task.resume()
}
}
}
Usage example
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "Identifier")
cell.title = "Cool title"
imageLoader.obtainImageWithPath(imagePath: viewModel.image) { (image) in
// Before assigning the image, check whether the current cell is visible
if let updateCell = tableView.cellForRow(at: indexPath) {
updateCell.imageView.image = image
}
}
return cell
}
Here is the swift version (by using #Nitesh Borad objective C code) :-
if let img: UIImage = UIImage(data: previewImg[indexPath.row]) {
cell.cardPreview.image = img
} else {
// The image isn't cached, download the img data
// We should perform this in a background thread
let imgURL = NSURL(string: "webLink URL")
let request: NSURLRequest = NSURLRequest(URL: imgURL!)
let session = NSURLSession.sharedSession()
let task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
let error = error
let data = data
if error == nil {
// Convert the downloaded data in to a UIImage object
let image = UIImage(data: data!)
// Store the image in to our cache
self.previewImg[indexPath.row] = data!
// Update the cell
dispatch_async(dispatch_get_main_queue(), {
if let cell: YourTableViewCell = tableView.cellForRowAtIndexPath(indexPath) as? YourTableViewCell {
cell.cardPreview.image = image
}
})
} else {
cell.cardPreview.image = UIImage(named: "defaultImage")
}
})
task.resume()
}
The best answer is not the correct way to do this :(. You actually bound indexPath with model, which is not always good. Imagine that some rows has been added during loading image. Now cell for given indexPath exists on screen, but the image is no longer correct! The situation is kinda unlikely and hard to replicate but it's possible.
It's better to use MVVM approach, bind cell with viewModel in controller and load image in viewModel (assigning ReactiveCocoa signal with switchToLatest method), then subscribe this signal and assign image to cell! ;)
You have to remember to not abuse MVVM. Views have to be dead simple! Whereas ViewModels should be reusable! It's why it's very important to bind View (UITableViewCell) and ViewModel in controller.
In my case, it wasn't due to image caching (Used SDWebImage). It was because of custom cell's tag mismatch with indexPath.row.
On cellForRowAtIndexPath :
1) Assign an index value to your custom cell. For instance,
cell.tag = indexPath.row
2) On main thread, before assigning the image, check if the image belongs the corresponding cell by matching it with the tag.
dispatch_async(dispatch_get_main_queue(), ^{
if(cell.tag == indexPath.row) {
UIImage *tmpImage = [[UIImage alloc] initWithData:imgData];
thumbnailImageView.image = tmpImage;
}});
});
Thank you "Rob"....I had same problem with UICollectionView and your answer help me to solved my problem.
Here is my code :
if ([Dict valueForKey:#"ImageURL"] != [NSNull null])
{
cell.coverImageView.image = nil;
cell.coverImageView.imageURL=nil;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if ([Dict valueForKey:#"ImageURL"] != [NSNull null] )
{
dispatch_async(dispatch_get_main_queue(), ^{
myCell *updateCell = (id)[collectionView cellForItemAtIndexPath:indexPath];
if (updateCell)
{
cell.coverImageView.image = nil;
cell.coverImageView.imageURL=nil;
cell.coverImageView.imageURL=[NSURL URLWithString:[Dict valueForKey:#"ImageURL"]];
}
else
{
cell.coverImageView.image = nil;
cell.coverImageView.imageURL=nil;
}
});
}
});
}
else
{
cell.coverImageView.image=[UIImage imageNamed:#"default_cover.png"];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
MyCell *cell = [tableView dequeueReusableCellWithIdentifier:#"cell" forIndexPath:indexPath];
cell.poster.image = nil; // or cell.poster.image = [UIImage imageNamed:#"placeholder.png"];
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"http://myurl.com/%#.jpg", self.myJson[indexPath.row][#"movieId"]]];
NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (data) {
UIImage *image = [UIImage imageWithData:data];
if (image) {
dispatch_async(dispatch_get_main_queue(), ^{
MyCell *updateCell = (id)[tableView cellForRowAtIndexPath:indexPath];
if (updateCell)
updateCell.poster.image = image;
});
}
}
}];
[task resume];
return cell;
}
I think you want to speed up your cell loading at the time of image loading for cell in the background. For that we have done the following steps:
Checking the file exists in the document directory or not.
If not then loading the image for the first time, and saving it to
our phone document directory. If you don't want to save the image in the phone then you can load cell images directlyin the background.
Now the loading process:
Just include: #import "ManabImageOperations.h"
The code is like below for a cell:
NSString *imagestr=[NSString stringWithFormat:#"http://www.yourlink.com/%#",[dictn objectForKey:#"member_image"]];
NSString *docDir=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)objectAtIndex:0];
NSLog(#"Doc Dir: %#",docDir);
NSString *pngFilePath = [NSString stringWithFormat:#"%#/%#",docDir,[dictn objectForKey:#"member_image"]];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:pngFilePath];
if (fileExists)
{
[cell1.memberimage setImage:[UIImage imageWithContentsOfFile:pngFilePath] forState:UIControlStateNormal];
}
else
{
[ManabImageOperations processImageDataWithURLString:imagestr andBlock:^(NSData *imageData)
{
[cell1.memberimage setImage:[[UIImage alloc]initWithData: imageData] forState:UIControlStateNormal];
[imageData writeToFile:pngFilePath atomically:YES];
}];
}
ManabImageOperations.h:
#import <Foundation/Foundation.h>
#interface ManabImageOperations : NSObject
{
}
+ (void)processImageDataWithURLString:(NSString *)urlString andBlock:(void (^)(NSData *imageData))processImage;
#end
ManabImageOperations.m:
#import "ManabImageOperations.h"
#import <QuartzCore/QuartzCore.h>
#implementation ManabImageOperations
+ (void)processImageDataWithURLString:(NSString *)urlString andBlock:(void (^)(NSData *imageData))processImage
{
NSURL *url = [NSURL URLWithString:urlString];
dispatch_queue_t callerQueue = dispatch_get_main_queue();
dispatch_queue_t downloadQueue = dispatch_queue_create("com.myapp.processsmagequeue", NULL);
dispatch_async(downloadQueue, ^{
NSData * imageData = [NSData dataWithContentsOfURL:url];
dispatch_async(callerQueue, ^{
processImage(imageData);
});
});
// downloadQueue=nil;
dispatch_release(downloadQueue);
}
#end
Please check the answer and comment if there is any problem occurs....
Simply change,
dispatch_async(kBgQueue, ^{
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString: [NSString stringWithFormat:#"http://myurl.com/%#.jpg",[[myJson objectAtIndex:indexPath.row] objectForKey:#"movieId"]]]];
dispatch_async(dispatch_get_main_queue(), ^{
cell.poster.image = [UIImage imageWithData:imgData];
});
});
Into
dispatch_async(kBgQueue, ^{
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString: [NSString stringWithFormat:#"http://myurl.com/%#.jpg",[[myJson objectAtIndex:indexPath.row] objectForKey:#"movieId"]]]];
cell.poster.image = [UIImage imageWithData:imgData];
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadRowsAtIndexPaths:indexPaths withRowAnimation:UITableViewRowAnimationNone];
});
});
You can just pass your URL,
NSURL *url = [NSURL URLWithString:#"http://www.myurl.com/1.png"];
NSURLSessionTask *task = [[NSURLSession sharedSession] dataTaskWithURL:url completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (data) {
UIImage *image = [UIImage imageWithData:data];
if (image) {
dispatch_async(dispatch_get_main_queue(), ^{
yourimageview.image = image;
});
}
}
}];
[task resume];
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
Static NSString *CellIdentifier = #"Cell";
QTStaffViewCell *cell = (QTStaffViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
If (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"QTStaffViewCell" owner:self options:nil];
cell = [nib objectAtIndex: 0];
}
StaffData = [self.staffArray objectAtIndex:indexPath.row];
NSString *title = StaffData.title;
NSString *fName = StaffData.firstname;
NSString *lName = StaffData.lastname;
UIFont *FedSanDemi = [UIFont fontWithName:#"Aller" size:18];
cell.drName.text = [NSString stringWithFormat:#"%# %# %#", title,fName,lName];
[cell.drName setFont:FedSanDemi];
UIFont *aller = [UIFont fontWithName:#"Aller" size:14];
cell.drJob.text = StaffData.job;
[cell.drJob setFont:aller];
if ([StaffData.title isEqualToString:#"Dr"])
{
cell.drJob.frame = CGRectMake(83, 26, 227, 40);
}
else
{
cell.drJob.frame = CGRectMake(90, 26, 227, 40);
}
if ([StaffData.staffPhoto isKindOfClass:[NSString class]])
{
NSURL *url = [NSURL URLWithString:StaffData.staffPhoto];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url
completionHandler:^(NSURL *location,NSURLResponse *response, NSError *error) {
NSData *imageData = [NSData dataWithContentsOfURL:location];
UIImage *image = [UIImage imageWithData:imageData];
dispatch_sync(dispatch_get_main_queue(),
^{
cell.imageView.image = image;
});
}];
[task resume];
}
return cell;}

Resources