UICollectionView freezes iOS app - ios

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)

Related

Images in cell are changing everytime when tableview is scrolled

In the below code whenever I am scrolling the tableview, images in each cell are changing, which shouldn't happen. Please help. Thanks in advance.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UserDetails *userDetails = [arrUserDetails objectAtIndex:indexPath.row];
static NSString *CellIdentifier = #"CustomCell";
__weak TableViewCell *cell = (TableViewCell *)[_tableViewUsername dequeueReusableCellWithIdentifier:CellIdentifier];
cell.tag = indexPath.row;
cell.userName.text = userDetails.userName;
[self.operationQueue addOperationWithBlock: ^ {
NSURL *aURL = [NSURL URLWithString:userDetails.userImageURL];
NSError *error = nil;
NSData *data = [NSData dataWithContentsOfURL:aURL options:nil error:&error];
UIImage *image = nil;
if (cell.tag == indexPath.row)
{
image = [UIImage imageWithData:data];
[[NSOperationQueue mainQueue] addOperationWithBlock: ^ {
cell.customImageView.image = image;
cell.customImageView.contentMode = UIViewContentModeScaleToFill;
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}];
}
}];
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UserDetails *userDetails = [arrUserDetails objectAtIndex:indexPath.row];
static NSString *CellIdentifier = #"CustomCell";
__weak TableViewCell *cell = (TableViewCell *)[_tableViewUsername dequeueReusableCellWithIdentifier:CellIdentifier];
cell.tag = indexPath.row;
cell.userName.text = userDetails.userName;
//Add Default placeholder
cell.customImageView.image = [UIImage imageNamed:#"Default.png"];
[self.operationQueue addOperationWithBlock: ^ {
NSURL *aURL = [NSURL URLWithString:userDetails.userImageURL];
NSError *error = nil;
NSData *data = [NSData dataWithContentsOfURL:aURL options:nil error:&error];
UIImage *image = nil;
if (cell.tag == indexPath.row)
{
image = [UIImage imageWithData:data];
[[NSOperationQueue mainQueue] addOperationWithBlock: ^ {
cell.customImageView.image = image;
cell.customImageView.contentMode = UIViewContentModeScaleToFill;
cell.accessoryType = UITableViewCellAccessoryCheckmark;
}];
}
}];
Add Default placeholder for image before loading it from url,As cells are being reused it takes the previous image
You can use SDWebImage.framework to load image
[cell.customImageView sd_setImageWithURL:[NSURL URLWithString:userDetails.userImageURL] placeholderImage:nil options:SDWebImageCacheMemoryOnly completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
if (image) {
[cell.customImageView setImage:image];
}
}];
You can use Afnetworking class for this .
Simply import #import "UIImageView+AFNetworking.h"
And use this line:-
[cell.imgProfile setImageWithURL:imgurl placeholderImage:[UIImage imageNamed:#""]];
Imgurl is the image Url which you are getting from response

Asynchronously set images in tableview

I have a TableView using custom cells. I initially was setting grabbing an image from a URL in the cellForRowAtIndexPath method
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
SimpleTableCell *cell = (SimpleTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
NSDictionary *dictObject = [places objectAtIndex:indexPath.row];
cell.nameLabel.text = [dictObject valueForKey:#"PlaceTitle"];
NSURL *url = [NSURL URLWithString:#"http://images1.fanpop.com/images/image_uploads/Mario-Kart-Wii-Items-mario-kart-1116309_600_600.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
cell.thumbnailImageView.image = image;
return cell;
}
but this was making my TableView scroll laggy. Once I removed the image fetch, it scrolled fine, so I know this is my problem.
My question is: how can I asynchronously fetch this image and set it in my cell? Is there an easy way to do this? Thanks!
Step 1: Have a cache containing images. Either just in memory, better on disk.
Step 2: When you need an image, call a method which either returns an image from the cache, or returns a default image and starts a download.
Step 3: When a download finishes, add the image to the cache. Then find out which rows need the image. Reload all the rows that reload the image.
The download should be done asynchronously using GCD. I would really recommend that you add the download code into a separate, reusable method so that you can handle download errors. Even if you don't do it now, you will do it later.
dataWithContentsOfURL is a synchronous method rather than asynchronous,as
Apple Documents described.
This method is ideal for converting data:// URLs to NSData objects, and can also be used for reading short files synchronously. If you need to read potentially large files, use inputStreamWithURL: to open a stream, then read the file a piece at a time.
In order to asynchronously load image,especially in tableViewCell,try use 3rd part Library SDWebImage
Use this code inside your tableviews cellforindexpath
NSURLRequest *req =[[NSURLRequest alloc]initWithURL:[NSURL URLWithString:#"yourimageurl.com"]];
[NSURLConnection sendAsynchronousRequest:req queue:[NSOperationQueue currentQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if(!error){
UIImage *image =[UIImage imageWithData:data];
cell.thumbnailImageView.image = image;
}
else{
//error
}
}];
Create UIImageView Class File (i named it to MJTableImageView).
in MJTableImageView.h File
#interface MJTableImageView : UIImageView< NSURLConnectionDelegate, NSURLConnectionDataDelegate >
{
NSMutableData *imageData ;
long long expectedLength;
NSURLConnection *currentConnection;
NSString *File_name;
}
#property(nonatomic,readonly)UIActivityIndicatorView *loadingIndicator;
#property(nonatomic)BOOL showLoadingIndicatorWhileLoading;
-(void)setImageUrl:(NSURL *)imageUrl fileName:(NSString *)name;
#end
in MJTableImageView.m File
-(void)setImageUrl:(NSURL *)imageUrl fileName:(NSString *)name
{
// discard the previous connection
if(currentConnection)
{
[currentConnection cancel];
}
File_name = name;
//reset current image
self.image = nil;
// if(_showLoadingIndicatorWhileLoading)
// {
//show the loading indicator
if(!_loadingIndicator)
{
CGFloat width = self.bounds.size.width*0.5;
_loadingIndicator = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake((self.bounds.size.width-width)/2, (self.bounds.size.height-width)/2, 25.0 , 25.0)];
_loadingIndicator.backgroundColor = [UIColor colorWithWhite:0.0 alpha:0.5];
_loadingIndicator.layer.cornerRadius = width*0.1;
}
[self startLoadingIndicator];
// }
// initialize the placeholder data
imageData = [NSMutableData data];
// start the connection
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:imageUrl];
request.cachePolicy = NSURLRequestUseProtocolCachePolicy;
currentConnection = [NSURLConnection connectionWithRequest:request delegate:self];
}
-(void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
//if the image view is reused in a table view for example to load another image previous image is discarded
if(connection != currentConnection)
{
[connection cancel];
[self cleanUp];
return;
}
// append new Data
[imageData appendData:data];
// show the partially loaded image
self.image = [UIImage imageWithData:imageData];
}
-(void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
expectedLength = response.expectedContentLength;
}
-(void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// clean up
[self cleanUp];
}
-(void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// show the full image
self.image = [UIImage imageWithData:imageData];
NSString *filename = [NSHomeDirectory() stringByAppendingFormat:#"/Documents/%#", File_name];
NSData *data = UIImagePNGRepresentation([UIImage imageWithData:imageData]);
[data writeToFile:filename atomically:YES];
// clean up
[self cleanUp];
}
-(void)cleanUp
{
// clean up
imageData = nil;
[self stopLoadingIndicator];
}
-(void)startLoadingIndicator
{
if(!_loadingIndicator.superview)
{
[self addSubview:_loadingIndicator];
}
[_loadingIndicator startAnimating];
}
-(void)stopLoadingIndicator
{
if(_loadingIndicator.superview)
{
[_loadingIndicator removeFromSuperview];
}
[_loadingIndicator stopAnimating];
}
I am using StoryBoard so i add ImageClass(MJTableImageView) file to UItableviewcell ImageView and set tag number to it.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
NSDictionary *dict = [self.arr objectAtIndex:indexPath.row];
UITableViewCell *cell = [self.MJTableView dequeueReusableCellWithIdentifier:#"MJImageCell"];
if(cell == nil)
{
}
UILabel *appName = (UILabel*)[cell.contentView viewWithTag:2];
appName.text = [dict valueForKey:#"trackName"];
MJTableImageView *imageview = (MJTableImageView *)[cell.contentView viewWithTag:1];
NSString *url = [dict valueForKey:#"artworkUrl60"];
NSString *filename = [NSHomeDirectory() stringByAppendingFormat:#"/Documents/%#",[dict valueForKey:#"trackName"] ];
NSData *data = [NSData dataWithContentsOfFile:filename];
if(data)
{
imageview.image = [UIImage imageWithData:data];
}
else
{
[imageview setImageUrl:[NSURL URLWithString:url] fileName:[dict valueForKey:#"trackName"]];
}
return cell;
}
For More details see Github Project MJTableImageSwift it is in Swift.

Lazy loading in uicollectionview

here is the code for my collectionview it is showing records but loading really please tell me how can i implement lazy loading on this i also have a placeholder pic in my project
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
CollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"MJCell" forIndexPath:indexPath];
// Setup image name
NSString *url = [[rssOutputData objectAtIndex:indexPath.row]xmllink];
UIImage *img = nil;
NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
img = [[UIImage alloc] initWithData:data];
cell.MJImageView.image = img;
return cell;
}
right now it is working but very very slow.
It's pretty easy to do lazy loading using GCD.
// Create a queue for the operations
dispatch_queue_t queue = dispatch_queue_create("photoList", NULL);
// Start getting the data in the background
dispatch_async(queue, ^{
NSData* photoData = [NSData dataWithContentsOfURL:[NSURL URLWithString:object.photoURL]];
UIImage* image = [UIImage imageWithData:photoData];
// Once we get the data, update the UI on the main thread
dispatch_sync(dispatch_get_main_queue(), ^{
cell.photoImageView.image = image;
});
});
The easiest way to implement that is use SDWebImage library, it does right what you need. There is UIImageView category that will allow you to modify code for that:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
CollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"MJCell" forIndexPath:indexPath];
// Setup image name
NSString *url = [[rssOutputData objectAtIndex:indexPath.row]xmllink];
[cell.MJImageView sd_setImageWithURL:[NSURL URLWithString:url]];
return cell;
}
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString: #"url.com"]];
UIActivityIndicatorView * indicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray];
[yourImageView addSubview:indicator];
indicator.center = yourImageView.center;
[indicator startAnimating];
[yourImageView setImageWithURLRequest:request
placeholderImage:[UIImage imageNamed:#"placeholder.png"]
success:^(NSURLRequest *request, NSHTTPURLResponse *response, UIImage *image) {
dispatch_async(dispatch_get_main_queue(), ^(void){
yourImageView.image = image;
});
[indicator stopAnimating];
[indicator removeFromSuperview];
} failure:nil];
Maybe, because your image is so large
You can use NSThread for loading
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
CollectionViewCell* cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"MJCell" forIndexPath:indexPath];
cell.tag = indexPath.row; //For index
[NSThread detachNewThreadSelector:#selector(loadImage:) toTarget:self withObject:cell];
return cell;
}
- (void) loadImage:(CollectionViewCell *)cell {
NSString *url = [[rssOutputData objectAtIndex:cell.tag]xmllink];
UIImage *img = nil;
NSData *data = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:url]];
img = [[UIImage alloc] initWithData:data];
cell.MJImageView.image = img;
}

Parse an image in to the Collection-view Custom cell in ios

i want to parse an image from web services and show onto the collection view custom cell for this i write a code as
in my .h file
#property(strong,nonatomic)IBOutlet UICollectionView *imagecollection;
#property(strong,nonatomic)NSArray *imagesa;
#property(strong,nonatomic)NSDictionary *json;
#property(strong,nonatomic)NSArray *aimages;
and in my .m file
#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0)
#define imageURL [NSURL URLWithString:#"http://www.truemanindiamagazine.com/webservice/gallery_image.php"]
- (void)viewDidLoad
{
[super viewDidLoad];
dispatch_async(kBgQueue, ^{
data = [NSData dataWithContentsOfURL: imageURL];
[self performSelectorOnMainThread:#selector(fetchedData:) withObject:data waitUntilDone:YES];
});
[self.imagecollection registerNib:[UINib nibWithNibName:#"Custumcell" bundle:nil] forCellWithReuseIdentifier:#"CellIdentifier"];
}
-(void)fetchedData:(NSData *)responsedata
{
NSError* error;
self.json = [NSJSONSerialization JSONObjectWithData:responsedata options:kNilOptions error:&error];
self.imagesa=[json objectForKey:#"data"];
NSLog(#"images,%#",self.imagesa);
}
-(NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView
{
return 1;
}
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section
{
return self.imagesa.count;
}
-(Custumcell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
Custumcell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"CellIdentifier" forIndexPath:indexPath];
UIImageView *img=[[UIImageView alloc]initWithFrame:CGRectMake(0,0,100,100)];
NSString *img2=[self.imagesa objectAtIndex:indexPath.row];
img.image=[UIImage imageNamed:img2];
cell.imageview.image=[UIImage imageNamed:img2];
return cell;
}
then images from web services is parsed but not shown into the collection view please give me any solution.
try to replace your
-(void)fetchedData:(NSData *)responsedata
{
NSError* error;
self.json = [NSJSONSerialization JSONObjectWithData:responsedata options:kNilOptions error:&error];
self.imagesa=[json objectForKey:#"data"];
NSLog(#"images,%#",self.imagesa);
}
with the code
-(void)fetchedData:(NSData *)responsedata
{
NSError* error;
self.json = [NSJSONSerialization JSONObjectWithData:responsedata options:kNilOptions error:&error];
self.imagesa=[json objectForKey:#"data"];
if (self.imagesa.count) {
dispatch_async(dispatch_get_main_queue(), ^{
[imagecollection reloadData];
});
}
NSLog(#"images,%#",self.imagesa);
}
now use SDWebImageDownloader and inside your cellForRowAtIndexpath method, replace your method cellForRowAtIndexPath with
Custumcell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"CellIdentifier" forIndexPath:indexPath];
NSDictionary *dict = [self.imagesa objectAtIndex:indexPath.item];
NSString *img2=[dict valueForKey:#"link"];
[cell.imageview sd_setImageWithURL:[NSURL URLWithString:[img2 stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]] placeholderImage:[UIImage imageNamed:#"temp.png"] options:SDWebImageProgressiveDownload completed:^(UIImage *image, NSError *error, SDImageCacheType cacheType, NSURL *imageURL) {
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(#"downloaded");
});
}];
return cell;
also import #import "UIImageView+WebCache.h" in your file
May be this will help you.
#define kBgQueue dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
-(Custumcell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
Custumcell *cell=[collectionView dequeueReusableCellWithReuseIdentifier:#"CellIdentifier" forIndexPath:indexPath];
cell.imageview.image= nil; // or cell.poster.image = [UIImage imageNamed:#"placeholder.png"];
dispatch_async(kBgQueue, ^{
NSData *imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[[self.imagesa objectAtIndex:indexPath.row] objectForKey:#"link"]]];
if (imgData) {
UIImage *image = [UIImage imageWithData:imgData];
if (image) {
dispatch_async(dispatch_get_main_queue(), ^{
Custumcell *updateCell = (id)[collectionView cellForItemAtIndexPath:indexPath];
if (updateCell)
updateCell.imageview.image = image;
});
}
}
});
return cell;
}

CollectionView NSURL Session Speed and Reloading

I'm fairly new to iOS and developing weather App in when I download hourly forecast along with icon of conditions. I have been able to implement UICollection with NSURL Connection. However, I'm having issues regarding speed/performance issues regarding NSURL Session. Here are the two issues:
1) the speed of downloading and presenting the downloaded icons is very slow (and there are extremely small images). This download process can take anywhere from 5-10 seconds.
2) when I put a button to reset the collection, all data is reset, however the existing images remain until the new images are downloaded. Again this can take anywhere from 5-10 seconds.
Here is my code:
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.hours.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"ConditionsCell";
ConditionsCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
cell.conditionsTime.text = [self.hours objectAtIndex:indexPath.row];
cell.conditionsTemp.text = [NSString stringWithFormat:#"%#°", [self.hoursTemp objectAtIndex:indexPath.row]];
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString:[self.hoursIcons objectAtIndex:indexPath.row]] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
UIImage * serverImage = [UIImage imageWithData: data];
cell.conditionsImage.image = serverImage;
}];
[dataTask resume];
return cell;
}
And here is the IBAction for the button and to reload the CollectionView:
- (IBAction)selectDay:(UISegmentedControl *)sender {
if (sender.selectedSegmentIndex == 0)
{
self.todayOrTomorrow = #"today";
}
else if (sender.selectedSegmentIndex == 1)
{
self.todayOrTomorrow = #"tomorrow";
}
self.hours = [self hours];
self.hoursIcons = [self hoursIcons];
self.hoursTemp = [self hoursTemp];
[_collectionViewHours reloadData];
}
You are downloading data in background that, but not updating UI on main thread,try below pattern it willlhelp you
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"ConditionsCell";
ConditionsCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
cell.conditionsTime.text = [self.hours objectAtIndex:indexPath.row];
cell.conditionsTemp.text = [NSString stringWithFormat:#"%#°", [self.hoursTemp objectAtIndex:indexPath.row]];
cell.conditionsImage.image = [UIImage imageNamed:""];//reseting image
NSURLSession *session = [NSURLSession sharedSession];
NSURLSessionDataTask *dataTask = [session dataTaskWithURL:[NSURL URLWithString: [self.hoursIcons objectAtIndex:indexPath.row]] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
#autoreleasepool {//autorelease pool for memory release
if (!error) {
//UIImage * serverImage = [UIImage imageWithData: data];//comment this extra variable and can increase memory overhead.
dispatch_async(dispatch_get_main_queue(), ^{
cell.conditionsImage.image = [UIImage imageWithData: data];//update UI
});
}}//autorelease pool
}];
[dataTask resume];
return cell;
}
it will definetly help you for your first part.
Thanks.

Resources