Appending image in collectionView using AFNetworking - ios

I am new for Ios app development. I am using AFNetworking for image and data load, data are binned in collection view but unable to bind image.
This is my code for collection view and service:
#import "ViewController.h"
#import "LabelCollectionViewCell.h"
#interface ViewController ()
{
NSMutableArray *idArray;
NSMutableArray *namelabelArray;
UIImage *imagArray;
NSMutableArray *dic ;
}
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
[[self userCollection]setDataSource:self];
[[self userCollection]setDelegate:self];
[self dataJson];
NSLog(#"array: %#", namelabelArray);
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
-(NSInteger) collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return [namelabelArray count];
}
-(UICollectionViewCell *) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"cell";
LabelCollectionViewCell *customCell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
[[customCell nameLabel]setText:[namelabelArray objectAtIndex:indexPath.item]];
[[customCell idLabel]setText:[idArray objectAtIndex:indexPath.item]];
return customCell;
}
-(void)dataJson
{
NSString *zipcode;
NSString *url = [NSString stringWithFormat:#"%#",#"http://inveera.biz/lowkall_api/index.php/product_cat"];
NSDictionary *params =[NSDictionary dictionaryWithObjectsAndKeys: zipcode,#"35005",nil];
NSLog(#"Login URL %#", params);
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
[manager POST:url parameters:params success:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Login JSON: %#", responseObject);
NSString *data = [responseObject valueForKey:#"data"];
idArray = [data valueForKey:#"id"];
namelabelArray =[data valueForKey:#"name"];
imagArray =[data valueForKey:#"img_path"];
NSLog(#"Error image: %#", imagArray);
[self.userCollection reloadData];
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"Error: %#", error);
}];
}
My json response is
{
"status":"true",
"city":[{"cityname":"Acmar"}],
"data":[
{"id":"1","name":"Appliances","img_path":"categories\/1\/ac1.png","status":"1"},
{"id":"2","name":"Electronics","img_path":"categories\/2\/ac2.png","status":"1"},
{"id":"3","name":"Furniture","img_path":"categories\/3\/ac3.png","status":"1"},
{"id":"4","name":"Cars","img_path":"categories\/4\/ac4.png","status":"1"},
{"id":"5","name":"Pet Supplies","img_path":"categories\/5\/ac5.png","status":"1"},
{"id":"6","name":"Others","img_path":"categories\/6\/ac6.png","status":"1"}
]
}
I am able to bind name but unable to bind image with full path with domain
name.
Please help me out. Thanks in advance.

In AFNetworking Lib itself they have added one category class for UIImageView called UIImageView+AFNetworking to load images from URL, You need call below method with valid URL request.
- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest
placeholderImage:(UIImage *)placeholderImage
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure
-(UICollectionViewCell *) collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *cellIdentifier = #"cell";
LabelCollectionViewCell *customCell = [collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier forIndexPath:indexPath];
[[customCell nameLabel]setText:[namelabelArray objectAtIndex:indexPath.item]];
[[customCell idLabel]setText:[idArray objectAtIndex:indexPath.item]];
[[customCell imageView] setImageWithURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:[imagArray objectAtIndex:indexPath.row]]]
placeholderImage:nil
success:nil
failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) {
}];
return customCell;
}

First of all, instead of UIImage *imageArray; it should be NSString *imageURLString;
and then since you are using AFNetworking better to load images async (use #import UIImageView+AFNetworking.h).
NSURL *imageURL = [NSURL URLWithString:[NSString stringWithFormat:#"%#%#", self.baseURL, imageURLString]];
[self setImageWithURLRequest:[NSURLRequest requestWithURL:imageURL]
placeholderImage:placeholder
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
if (image)
{
weakSelf.image = image;
}
} failure:^(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error) {
}];

Related

Data dosen't load on some Tableview cell from JSON parse

I making here simple application on XCODE 7.1. I just display 2 label and 1 image in tableview cell.I am parsing data from this URL. I am simply load data in TableviewHere i put the code of ViewController.m file
#interface ViewController ()
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
activityIndicator.alpha = 1.0;
[self.view addSubview:activityIndicator];
activityIndicator.center = CGPointMake([[UIScreen mainScreen]bounds].size.width/2, [[UIScreen mainScreen]bounds].size.height/2);
[activityIndicator startAnimating];//to start animating
// Do any additional setup after loading the view, typically from a nib.
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURL *URL = [NSURL URLWithString:#"http://www.androidbegin.com/tutorial/jsonparsetutorial.txt"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
NSLog(#"Error: %#", error);
} else {
[activityIndicator stopAnimating];
_responsedic = (NSDictionary*) responseObject;
_Worldpopulation = [_responsedic valueForKey:#"worldpopulation"];
_imageURL = [_Worldpopulation valueForKey:#"flag"];
_country = [_Worldpopulation valueForKey:#"country"];
_population = [_Worldpopulation valueForKey:#"population"];
NSLog(#"Data:%#",_imageURL);
NSLog(#"Population",_population);
NSLog(#"Country",_country);
// NSLog(#"%#",_MovieList);
//NSLog(#"Array: %#",_imageURL);
//NSLog(#"%#",responseObject);
}
}];
[dataTask resume];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(NSInteger) tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return 10;
}
-(UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSString *Identifier = #"mycell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:Identifier];
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:Identifier];
// Set and load the images
[cell.imageView sd_setImageWithURL:[_imageURL objectAtIndex:indexPath.row] placeholderImage:nil completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
// Get rid of the activity indicator when the image has been loaded
}];
cell.textLabel.text = [_country objectAtIndex:indexPath.row];
cell.detailTextLabel.text = [_population objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
//NSString *rowValue = self.friends[indexPath.row+1];
NSString *message = [[NSString alloc] initWithFormat:#"You selected %#",[_country objectAtIndex:indexPath.row]];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"YOU SELECT"
message:message
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
I am using AFNetworking 3.0 and SDWebImage for image loading.Data parse successfully and and displayed in tableview.I attached screenshot below
Problem is what the all data are not displayed in the tableview cell i also put the Alert dialog on each cell of tableview data successfully loaded but not displayed in cell. I search everywhere i can't find solution for this i am using 3G connection so net speed is not an issue Please someone help.
Try to reload table view with updated data in completion block.
NSURL *URL = [NSURL URLWithString:#"http://www.androidbegin.com/tutorial/jsonparsetutorial.txt"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:request completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) {
if (error) {
NSLog(#"Error: %#", error);
} else {
[activityIndicator stopAnimating];
_responsedic = (NSDictionary*) responseObject;
_Worldpopulation = [_responsedic valueForKey:#"worldpopulation"];
_imageURL = [_Worldpopulation valueForKey:#"flag"];
_country = [_Worldpopulation valueForKey:#"country"];
_population = [_Worldpopulation valueForKey:#"population"];
NSLog(#"Data:%#",_imageURL);
NSLog(#"Population",_population);
NSLog(#"Country",_country);
// NSLog(#"%#",_MovieList);
//NSLog(#"Array: %#",_imageURL);
//NSLog(#"%#",responseObject);
//Added Code -> Reloading data on Main queue for update
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableview reloadData];
});
}
}];
[dataTask resume];
Hope, it'll help you.
Thanks.
1) Parse Data and after getting data relaod table
-(void)ParseData
{
NSURLSession * session = [NSURLSession sharedSession];
NSURL * url = [NSURL URLWithString: #"http://www.androidbegin.com/tutorial/jsonparsetutorial.txt"];
//Create URLReques
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
[request addValue:#"application/x-www-form-urlencoded" forHTTPHeaderField:#"Content-Type"];
// Set Method POST/GET
[request setHTTPMethod:#"GET"];
// Asynchronously Api is hit here
NSURLSessionDataTask* dataTask=[session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
if (!error) //If error nil
{
//Serialization data
NSDictionary * json = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
NSLog(#"json %#",json);
array=[json valueForKey:#"worldpopulation"];
dispatch_async(dispatch_get_main_queue(), ^(void) {
if(array.count!=0)
{
//Reload table View
[_tblView reloadData];
}
});
}
else
{
//failure;
}
}];
[dataTask resume] ; // Executed task
}
2) Table View DataSource
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
if(array.count!=0)
{
return [array count];
}
return 0;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell;
//= [[UITableViewCell alloc]initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
cell.backgroundColor =[UIColor whiteColor];
cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
UILabel *lblCountry=(UILabel*)[cell viewWithTag:2];
lblCountry.text= [[array objectAtIndex:indexPath.row]valueForKey:#"country"];
UILabel *lblPopulation=(UILabel*)[cell viewWithTag:3];
lblPopulation.text= [[array objectAtIndex:indexPath.row]valueForKey:#"population"];
UIImageView *img = (UIImageView *)[cell viewWithTag:1];
[img setImageWithURL:[NSURL URLWithString:[[array objectAtIndex:indexPath.row]valueForKey:#"flag"]]];
return cell;
}

UICollectionView freezes iOS app

Good morning,
I'm using UICollectionView for the first time to show images from a user (like a Facebook profile) and at the moment I can show the images fine but I have some problems:
1- When I visit my profile the app freezes for like 2-3 minutes due to the load of 5 images.
2- When I'm moving through the UICollectionView it freezes when the app load again the images outside the screen.
What I have to do in order to not to freeze the app when loading the user pictures? And what I have to do to navigate through the CollectionView without freezing? Maybe a cache system is what I need?
That's my code:
ProfileViewController.m
- (void)viewDidLoad {
[super viewDidLoad];
[self.view setBackgroundColor: [self colorWithHexString:#"FFFFFF"]];
self.profileimage.layer.cornerRadius = self.profileimage.frame.size.width / 2;
self.profileimage.clipsToBounds = YES;
self.profileimage.layer.borderWidth = 1.0f;
self.profileimage.layer.borderColor = [UIColor whiteColor].CGColor;
[self fetchJson];
[self fetchImages];
self.oneCollectionView.dataSource = self;
self.oneCollectionView.delegate = self;
}
- (CGFloat)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout minimumLineSpacingForSectionAtIndex:(NSInteger)section
{
return 1;
}
-(NSInteger)numberOfSectionsInCollectionView: (UICollectionView *)collectionView
{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return _carImages.count;
}
// COLLECTION VIEW
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MyCollectionViewCell *myCell = [collectionView
dequeueReusableCellWithReuseIdentifier:#"MyCell"
forIndexPath:indexPath];
NSString *data = [[_jsonArray objectAtIndex:indexPath.row] valueForKey:#"imagen"];
NSURL * imageURL = [NSURL URLWithString:data];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage * images = [UIImage imageWithData:imageData];
myCell.imageview.image = images;
return myCell;
}
-(void)fetchImages {
self.carImages = [[NSMutableArray alloc] init];
NSString *usersPassword = [SSKeychain passwordForService:#"login" account:#"account"];
NSString * urlString = [NSString stringWithFormat:#"http://mywebsite.com/posts.php?usersPassword=%#",usersPassword];
NSURL * url = [NSURL URLWithString:urlString];
NSData * data = [NSData dataWithContentsOfURL:url];
NSError *error;
[_jsonArray removeAllObjects];
_jsonArray = [NSJSONSerialization
JSONObjectWithData:data
options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves
error:&error];
for(int i=0;i<_jsonArray.count;i++)
{
NSDictionary * jsonObject = [_jsonArray objectAtIndex:i];
NSString* imagen = [jsonObject objectForKey:#"imagen"];
[_carImages addObject:imagen];
}
}
Thanks in advance.
Import UIImageView+AFNetworking.h
and load your image via this method in cellForItemAtIndexPath method
[imageView setImageWithURL:[NSURL URLWithString:#"https://lh6.googleusercontent.com/-B8kSXtoaQDo/VGTVlXyIXpI/AAAAAAAAJ_M/USh6SgvMemw/w1024-h1024/IMG_20141112_103152.jpg"] placeholderImage:[UIImage imageNamed:#"placeholder-avatar"]];
it will surely speed up to load and scrolling collectionView
Download the images asynchronously, dataWithContentsOfURL is synchronous method and it will block your current thread until the download completes. You can use libraries like SDWebImage to automatically handle downloading for you or You can use NSURLSessionDownloadTask to download Images.
- (void)fetchImages {
self.carImages = [[NSMutableArray alloc] init];
NSString *usersPassword = [SSKeychain passwordForService:#"login" account:#"account"];
NSString * urlString = [NSString stringWithFormat:#"http://mywebsite.com/posts.php?usersPassword=%#",usersPassword];
NSURL * url = [NSURL URLWithString:urlString];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:url completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error) {
[self.jsonArray removeAllObjects];
self.jsonArray = [NSJSONSerialization
JSONObjectWithData:data
options:NSJSONReadingMutableContainers|NSJSONReadingMutableLeaves
error:&error];
for(int i=0;i<_jsonArray.count;i++)
{
NSDictionary * jsonObject = self.jsonArray[i];
NSString* imagen = jsonObject[#"imagen"];
[self.carImages addObject:imagen];
}
}
}];
[dataTask resume];
}
// COLLECTION VIEW
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MyCollectionViewCell *myCell = [collectionView
dequeueReusableCellWithReuseIdentifier:#"MyCell"
forIndexPath:indexPath];
NSString *data = [[self.jsonArray objectAtIndex:indexPath.row] valueForKey:#"imagen"];
NSURL * imageURL = [NSURL URLWithString:data];
NSURLSessionDownloadTask *imageDownloadTask = [[NSURLSession sharedSession]
downloadTaskWithURL:imageURL completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
UIImage *image = [UIImage imageWithData:
[NSData dataWithContentsOfURL:location]];
myCell.imageview.image = image;
}];
[imageDownloadTask resume];
return myCell;
}
You can use the dispatcher to create an async operation for the download of the images. This will resolve the 2 problems you have:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *imgData = [NSData dataWithContentsOfURL:YOUR_IMAGE_URL];
UIImage *img = [UIImage imageWithData:imgData];
[YOUR_IMAGE_VIEW_OUTLET performSelectorOnMainThread:#selector(setImage:) withObject:img waitUntilDone:YES];
});
These are the snippet you have to change:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MyCollectionViewCell *myCell = [collectionView
dequeueReusableCellWithReuseIdentifier:#"MyCell"
forIndexPath:indexPath];
NSString *data = [[_jsonArray objectAtIndex:indexPath.row] valueForKey:#"imagen"];
NSURL * imageURL = [NSURL URLWithString:data];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *imageData = [NSData dataWithContentsOfURL: imageURL];
UIImage *img = [UIImage imageWithData:imageData];
[myCell.imageview performSelectorOnMainThread:#selector(setImage:) withObject:img waitUntilDone:YES];
});
return myCell;
}
Try to Register Nib For Collection View
Write following code in your viewController's viewDidLoad()method :
UINib *nib = [UINib nibWithNibName:#"MyCollectionCell" bundle: nil];
[self.collectionView registerNib:nib forCellWithReuseIdentifier:#"Cell"];
And I think you have to use https://github.com/nicklockwood/AsyncImageView for the image loading in collection view.
For Storyboards you have to see this tutorial : http://www.appcoda.com/ios-programming-uicollectionview-tutorial/ This will help you more.
Thanks!
For the first question the answer is in this line of code:
NSData * data = [NSData dataWithContentsOfURL:url];
From Apple Reference:
Do not use this synchronous method to request network-based URLs. For
network-based URLs, this method can block the current thread for tens
of seconds on a slow network, resulting in a poor user experience, and
in iOS, may cause your app to be terminated.
As alternative you can use NSURLSessionDataTask to download data (see Apple Reference)
-Edit
In ProfileViewController.h add these two properties:
#property (nonatomic, strong) NSURLSessionConfiguration *sessionConfig;
#property (nonatomic, strong) NSURLSession *session;
then, in - viewDidLoad initialise them:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view
self.sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
self.session = [NSURLSession sessionWithConfiguration:self.sessionConfig];
//Other stuff...
}
Finally, in ProfileViewController.m
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MyCollectionViewCell *myCell = [collectionView
dequeueReusableCellWithReuseIdentifier:#"MyCell"
forIndexPath:indexPath];
NSString *data = [[_jsonArray objectAtIndex:indexPath.row] valueForKey:#"imagen"];
NSURL * imageURL = [NSURL URLWithString:data];
NSURLSessionDownloadTask *imageDownloadTask = [self.session dataTaskWithURL:imageURL
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (error) {
NSLog(#"ERROR: %#", error);
} else {
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if (httpResponse.statusCode == 200) {
UIImage *image = [UIImage imageWithData:data];
myCell.imageview.alpha = 0.0f;
myCell.imageview.image = image;
[UIView animateWithDuration:0.45 animations:^{
myCell.imageview.alpha = 1.0f;
});
} else {
NSLog(#"Couldn't load image at URL: %#", imageURL);
NSLog(#"HTTP %d", (int)httpResponse.statusCode);
}
}
}];
[imageDownloadTask resume];
return myCell;
}
I hope this can help you.
- Edit 2
For future readers, I slightly refactored my code based on #suhit's answer (+1 for him)

AFNetworking downloading thousands asynchronous images slows down app

I am downloading thousands of images asynchronously through AFNetworking an storing them in iDevice but my app goes slow down when errors shows on console "Response time out"
following is the code that I used to download images.
[NSThread detachNewThreadSelector:#selector(DownloadImages) toTarget:self withObject:nil];
-(void)DownloadImages
{
for(int i = 0; i<=4600;i++)
{
NSString *FrameSmall = [NSString stringWithFormat:#"myimageurl%i.png",i];
[self setbuttonImg:FrameSmall];
}
}
-(void)setbuttonImg:(NSString *)str
{
NSArray* badWords = #[#":", #"/", #".",#" "];
NSMutableString* mString = [NSMutableString stringWithString:str];
for (NSString* string in badWords) {
mString = [[mString stringByReplacingOccurrencesOfString:string withString:#""] mutableCopy];
}
NSString *encoded = [str stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:encoded]];
AFHTTPRequestOperation *requestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest];
requestOperation.responseSerializer = [AFImageResponseSerializer serializer];
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSString * documentsDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
[self saveImage:responseObject withFileName:mString ofType:#"png" inDirectory:documentsDirectoryPath];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
}];
[requestOperation start];
}
-(void) saveImage:(UIImage *)image withFileName:(NSString *)imageName ofType:(NSString *)extension inDirectory:(NSString *)directoryPath {
if ([[extension lowercaseString] isEqualToString:#"png"]) {
[UIImagePNGRepresentation(image) writeToFile:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#", imageName, #"png"]] options:NSAtomicWrite error:nil];
} else if ([[extension lowercaseString] isEqualToString:#"jpg"] || [[extension lowercaseString] isEqualToString:#"jpeg"]) {
[UIImageJPEGRepresentation(image, 1.0) writeToFile:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#", imageName, #"jpg"]] options:NSAtomicWrite error:nil];
} else {
// ALog(#"Image Save Failed\nExtension: (%#) is not recognized, use (PNG/JPG)", extension);
}
}
All of your images are being downloaded at the same time which isn't a good idea.
You can set the max concurrency with the operationQueue on the AFHTTPRequestOperationManager
http://cocoadocs.org/docsets/AFNetworking/2.0.0/Classes/AFHTTPRequestOperationManager.html#//api/name/operationQueue
AFHTTPRequestOperationManager *manager = [AFHTTPRequestOperationManager manager];
manager.operationQueue.maxConcurrentOperationCount = 5; //set to max downloads at once.
Best practice would be to only load images that your user is going to see immediately - so the ones in view only. Typically that means just storing the URL, then loading the image when its actually needed. Using just a custom category on UIImageView (AFNetworking provides a similar category) you can load an image into a custom table view cell using:
- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest
placeholderImage:(UIImage *)placeholderImage
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse *response, NSError *error))failure;
Here's an example with a custom wrapper around that category:
- (void)tableView:(UITableView *)tableView
willDisplayCell:(GameTableViewCell *)cell
forRowAtIndexPath:(NSIndexPath *)indexPath
{
cell.backgroundColor = [UIColor clearColor];
id game = [self.games objectAtIndex:indexPath.row];
if([game isKindOfClass:[Game class]])
{
Game *aGame = (Game *)game;
cell.titleLabel.text = aGame.gameName;
cell.descriptionLabel.text = aGame.gameDescription;
cell.playGameButton.layer.cornerRadius = 8.0F;
[cell.imageView loadImageFromRemoteURL:aGame.imageURL
withPlaceholder:[UIImage imageFromAssetsNamed:#"game_icon"]
completionHandler:^(UIImage *fetchedImage, NSError *error)
{
if(nil == error)
{
aGame.image = fetchedImage;
// Note: Need to set the image in an imageView somewhere on the main thread.
}
}];
}
}
This means that only game cells on screen will have their images loaded rather than loading them all at once.

After reloading UITableView data, indexPathForCell returns null

I have a UITableView in a ViewController which contains a custom cell.
When the view first loads, the indexPathForCell in the following code returns the indexPath without problems:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
PostCell *postCell = (PostCell *)[tableView dequeueReusableCellWithIdentifier:#"PostCell"];
if (postCell == nil) {
NSLog(#"EmptyCell Found");
}
NSDictionary *object = [postArray objectAtIndex:indexPath.row];
NSString *imageURL = [object objectForKey:#"imageURL"];
NSIndexPath *originalIndexPath = indexPath;
NSLog(#"Original IndexPath %#", originalIndexPath);
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadWithURL:[NSURL URLWithString:imageURL]
options:indexPath.row == 0 ? SDWebImageRefreshCached : 0
progress:^(NSInteger receivedSize, NSInteger expectedSize){}
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished){
if (image) {
// This returns correctly on first load
NSIndexPath *currentIndexPath = [imageTableView indexPathForCell:postCell];
NSLog(#"Current IndexPath %#", currentIndexPath);
}
}
];
}
After refreshing the tableView, currentIndexPath is always (null).
The following is my refresh code:
- (void)refreshMainView {
AFHTTPRequestOperation *downloadPostOperation = [[AFHTTPRequestOperation alloc] initWithRequest:serviceRequest];
[downloadPostOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
//[tableView beginUpdates];
NSDictionary *json = [NSJSONSerialization JSONObjectWithData:urlData options:kNilOptions error:&error];
NSMutableArray *newPostArray = [json objectForKey:#"posts"];
// Replacing the old array with new array
postArray = newPostArray;
[self stopRefresh];
//[tableView endUpdates]
[imageTableView reloadData];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
[self stopRefresh];
}];
If I just perform [tableView reloadData] without performing refreshMainView, there will not be any problem with getting the currentIndexPath.
There must be something I am overlooking, could someone please help me? Thank you!
Edit:
I have tried [postCell.postImageView setImageWithURL:[NSURL URLWithString:imageURL] placeholderImage:nil]; instead and the refreshing works, so I am suspecting that something is wrong with me getting the indexPath in the completed block, can anyone help out please? I need the completed block as I am doing some image processing.
Hi I have finally fixed it.
For people who are needing answers, just add
dispatch_async(dispatch_get_main_queue(), ^{
});
around the portion that is retrieving the indexPathForCell.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
PostCell *postCell = (PostCell *)[tableView dequeueReusableCellWithIdentifier:#"PostCell"];
if (cell == nil)
{
nib = [[NSBundle mainBundle] loadNibNamed:#"PostCell" owner:self options:nil];
}
NSIndexPath *originalIndexPath = indexPath;
NSLog(#"Original IndexPath %#", originalIndexPath);
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadWithURL:[NSURL URLWithString:imageURL]
options:indexPath.row == 0 ? SDWebImageRefreshCached : 0
progress:^(NSInteger receivedSize, NSInteger expectedSize){}
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished){
if (image) {
// This returns correctly on first load
NSIndexPath *currentIndexPath = [imageTableView indexPathForCell:postCell];
NSLog(#"Current IndexPath %#", currentIndexPath);
}
}
];
use this it may help you

SDWebImage With Custom UITableView Cell Image

I am trying to use SDWebImage library with a custom UITableViewCell. Below is the method that is downloading the images from the web service:
- (void) downloadThumbnails:(NSURL *)finalUrl
{
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadWithURL:finalUrl
options:0
progress:nil
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished)
{
if (image)
{
// do something with image
// THERE I HAVE TO ASSIGN the property "thumbnail" with the "image"
// So it can be used by the tableview controller class
}
}];
}
The above code is in a separate file named RSSItem. While my UITableViewController class has the following cellForRowAtIndexPath method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"ItemsCell";
ItemsViewCell *cell = (ItemsViewCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
RSSItem *item = [[channel items] objectAtIndex:[indexPath row]];
cell.titleLabel.text = [item title];
cell.creatorLabel.text = [item creator];
cell.pubTimeLabel.text = [item pubTime];
cell.thumbContainer.image = [item thumbnail];
return cell;
}
Can somebody point out how can i configure the if (image) inside downloadThumbnails method? I just need to assign "image" to the property "thumbnail", how can i do that?
Looks like you have already used the right method to download images asynchronously using SDWebImage. All you need to do is to set the thumbnail property to the "image". Here is how you can do it:
- (void) downloadThumbnails:(NSURL *)finalUrl
{
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadWithURL:finalUrl
options:0
progress:nil
completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, BOOL finished)
{
if (image)
{
[self setThumbnail:image];
}
}];
}

Resources