I am working on lazy load of images for UICollectionView. The Image are showing but when I scroll the UICollectionView, images change their positions and there are repetition of images where all the images should be unique. Here is my code:
- (gridcell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
gridcell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"gallerycollection" forIndexPath:indexPath];
NSDictionary *appsdict = [array_grid objectAtIndex:indexPath.item];
cell.image_grid.image=[UIImage imageNamed:#"griddummyloading"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
NSURL *imageURL = [NSURL URLWithString:[appsdict objectForKey:#"iosthumbnail"]];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *image = [UIImage imageWithData:imageData];
dispatch_async(dispatch_get_main_queue(), ^{
cell.image_grid.image=image;
});
});
[collectionview_grid setAllowsSelection:YES];
return cell;
}
I suggest you use a third party library to lazy load images, like this one, which also supports web caching.
Also, consider the conventions used in objective-c:
- avoid snake_casing, use camelCase
- make extensive use of properties
- use upper cased class names
Hey theres a very good example given at Apple developer site.
This is an example code where apple demonstrates a way of doing lazy loading in a table.. referring to this might help you out in some way.
All the best
Related
A tablview cell is being setup using the following code...
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
MyTableviewcell *cell = [tableView dequeueReusableCellWithIdentifier:#"mytableviewcell" forIndexPath:indexPath];
cell.titleLabel.text = [self.data[indexPath.row] objectForKey:#"node_title"];
cell.taxonomy1Label.text = [self.data[indexPath.row] objectForKey:#"group"];
#try {
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[self.data[indexPath.row] objectForKey:#"image"]]];
cell.thumbnailImageView.image = [UIImage imageWithData:imageData];
}
#catch (NSException * e) {
NSLog(#"Exception: %#", e);
}
return cell;
}
The try/catch are just because it may or may not have an image but it was happening even before I put that in. It seems like there is some sort of issue when it goes to dequeue the cell. Any ideas?
If you are familiar with using third party libraries or CocoaPods, but this is a common problem, and I recommend the use of https://github.com/rs/SDWebImage or https://github.com/AFNetworking/AFNetworking, which have UIImageView category methods to handle loading images from a URL in the background, and not in a main thread.
For example using SDWebImage:
[cell.thumbnailImageView sd_setImageWithURL:yourImageURL];
This method will fetch the image in the background, not blocking the main thread and will not make your UITableView jitter.
As already mentioned this call blocks the main thread:
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:[self.data[indexPath.row] objectForKey:#"image"]]];
What wasn't already mentioned is the right way to handle this kind of work.
You can't just wrap the above in a GCD call and expect everything to be OK.
You need to lazy load the images and populate them on the tableView when appropriate.
The most elegant way to handle this is to write your own NSOperation.
Here is a tutorial, any further questions let me know.
You are obstructing the main thread by trying to fetch image. Put your image call in a separate thread.
I am looking for a way to send rapid request using proxies to make a viewbot app. Any suggestions on how to efficiently do this or to make the most use of the proxies and the network ability would be really helpful. Currently my setup uses ASIHTTPRequest where i setup a request add it into an array and then I have a method that is constantly looping through these request and startAsynchronys.
could you simply use DLImageLoager, which takes care of all for you?
It is an incredibly well maintained library. We often use it to stack up 100s of calls, never a hiccup.
https://github.com/AndreyLunevich/DLImageLoader-iOS/tree/master/DLImageLoader
Example code for "set and forget" loading an image
-(UICollectionViewCell *)collectionView:(UICollectionView *)cv
cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
NSInteger thisRow = indexPath.row;
BooksCell *cell;
cell = [cv dequeueReusableCellWithReuseIdentifier:
#"CellBooksNormal" forIndexPath:indexPath];
cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
// set text items...
cell.title = #"blah";
// set image items using DLImageLoader
__weak UIBookView *loadMe = cell.anImage;
[DLImageLoader loadImageFromURL:imUrl
completed:^(NSError *error, NSData *imgData)
{
[loadMe use:[UIImage imageWithData:imgData]];
}];
return cell;
}
Currently I am loading all of my UITableViewControllers with images and text. I'm not sure if there is a way of shortening my loading times. I'm thinking that GCD might be the best route to go, however, I'm not too sure that I'm using this correctly:
dispatch_async(dispatch_get_main_queue(), ^{
[some method];
});
This is being loaded in the ViewDidLoad, and I'm unsure if this is the correct place to use GCD. Also, is this correct way of asynchronously loading information?
use this, it downloads multiple files in different threads.And its asynchronous.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//load image here
});
If you want to load all images ,even the images which might be very down in tableView (say image at 20th row).Then viewDidLoad is perfect approach, or if you want to only load images that are currently to be shown, then download images in cellForRow:atIndexPath method.
OR,you can use AFNetworking to download multiple files much efficiently.
Hope this helps
For loading images faster in table view cells you can use SDWebImage.
It is very simple to use. Just import the SDWebImage folder into your Xcode project. It contains a category on UIImageVIew. So on any imageView object just call the method setImageWithURL as illustrated below:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier] autorelease];
}
// Here we use the new provided setImageWithURL: method to load the web image
[cell.imageView setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
cell.textLabel.text = #"My Text";
return cell;
}
I am trying to grab images from external API and bind it to my UICollectionView & UIImageView cell with in that View. I am able to get the data and print it in the log file. However, I am not able to see the images on my UICollectionView. Here is the code to my data bindings.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
ImagesViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"Cell" forIndexPath:indexPath];
// imagesArray is an array with serialized json data.
NSDictionary *finalImages = [self.imagesArray objectAtIndex:indexPath.row];
NSLog(#"Entering collection view.....");
[[cell imageViewCell]setImage:[UIImage imageNamed:[finalImages valueForKey:#"link"]]];
return cell;
}
The is data is coming in JSON format.
data
{
abc: 'abc',
xyz: 'xyx',
link: 'link to an online image'
}
imageNamed is a method to get image from a image file in your bundle (image.png).
In the case you want to get image from URL, download it as Mr Richhard Brown answer or use SDWebImage(set directly with imageView)
Sample colectionView SDWebImage code(nonARC): https://github.com/lequysang/github_zip/blob/master/CollectionViewNonARC.zip
UIImage imageNamed: takes a filename, not a URL.
You need to manually load the image file into an NSData object before you can display it.
NSData dataWithContentsOfURL will do this for you.
UIImage *image = [UIImage imageWithData: [NSData dataWithContentsOfURL:[finalImages valueForKey:#"link"]]];
I am using a tableview which loads images from the documents directory, creates a thumbnail and shows it in the tableview. However, I have a problem: it becomes slow and crashes as the pictures are large, taken using the camera.
I have explored several solution including GCD to do the work in a background thread but the result is the same thing. So, I thought to look into SDWebImage but I don't know if it will also work for local files, not web images in this case. Can someone advise me please? If not, how is this problem solved? Is there an API that can help to resolve this issue?
That question is not easy to answer as the Question is asked fairly broad but I will do my best.
First, I usually dispatch a Background Thread if I have expensive processing to do as to not block the Main Thread, which is fairly important.
I don't really know why you are not using the normal UIImageView for what you are doing but try to implement following :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"YourCell";
MyCellClass *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[MyCellClass alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
/*
Whatever Code you want
*/
NSArray* params =#[cell.myImageView, #"http://myfancyimages.com/image.png"];
[self performSelectorInBackground:#selector(loadEventImageWithParameters:) withObject:params];
return cell;
}
And now add the function :
- (void) loadEventImageWithParameters:(id) parameters {
NSArray* params = [[NSArray alloc] initWithArray:(NSArray*)parameters];
NSURL *url = [NSURL URLWithString:[params objectAtIndex:0]];
UIImage *image = [UIImage imageWithData: [NSData dataWithContentsOfURL:url]];
UIImageView* theImageView = (UIImageView*) [params objectAtIndex:0];
[theImageView setImage:image];
}
If you got a lot of Pictures to load you are well advised to queue your Processes so you don;t "steal" all resources with Grand Central Dispatch.
Have a read through this excellent post http://www.raywenderlich.com/4295/multithreading-and-grand-central-dispatch-on-ios-for-beginners-tutorial for further details.
Hope that helped