I have a image url plist with 50 image urls.Iam trying to display that in a UICollectionview but it getting too slow.Iam displaying 9 cells(images) at a time like 3x3 (3 rows and 3 columns).How can i display first 9 images at loading time and next 9 images on next scrolling .?is that possible? i tried SDWebImages for loading images ,Its not working for me.Please help me.
CODE INSIDE collectionView cellForItemAtIndexPath: ()
the code inside comment take lots of time for loading image,that code is used for loading image from document directory if image is not there then i will display in one place holder image
cell = nil;
cell = (GMMCollectionViewCell *)[self.collectionView dequeueReusableCellWithReuseIdentifier:#"test" forIndexPath:indexPath];
cell.tag = indexPath.row;
docPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *path;
BOOL isImageLoaded = YES;
/////////////////////PROBLEM CODE:TAKING TOO MUCH TIME TO LOAD IMAGE //////////////////////
bookImage = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:#"%#/%#", docPath, [[allbooksImage objectAtIndex:indexPath.row] lastPathComponent]]];
//////////////////////////////////////////////////////////////////////////////////
if(bookImage == nil){
isImageLoaded = NO;
}
if(!isImageLoaded){
[[cell grid_image] setImage:[UIImage imageNamed:#"App-icon-144x144.png"]];
} else{
[[cell grid_image] setImage:bookImage];
}
sharedManager.bookID=bookId;
return cell;
This is what iam expecting
But iam getting like this ,
App Loading time Without any scroll (first image:3 columns are empty)
App screen after first scroll (second image:last column displaying 2 images ,rest of the part still empty )
App screen after a long scroll (third image: last colum some images are there ,rest of the columns still empty)
App screen again scroll to top,so the first image changed
You can try the below code
[[cell grid_image] setImage:nil];
dispatch_queue_t concurrentQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_async(concurrentQueue, ^{
bookImage = [UIImage imageWithContentsOfFile:[NSString stringWithFormat:#"%#/%#", docPath, [[allbooksImage objectAtIndex:indexPath.row] lastPathComponent]]];
dispatch_async(dispatch_get_main_queue(), ^{
if (bookImage)
{
[[cell grid_image] setImage:bookImage];
}
else
{
[[cell grid_image] setImage:[UIImage imageNamed:#"App-icon-144x144.png"]];
}
});
});
hope it will work for you.
Related
I have created collection view programmatically where i have created UIImageview programmatically within collectionViewCell and images are displayed in imageview are downloaded from server asynchronously.
Code below is written in cellForItemAtIndexPath: method -
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSURL *imageURL = [NSURL URLWithString:[arrmImgPaths objectAtIndex:indexPath.row]];
NSData *imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage *image = [UIImage imageWithData:imageData];
// [imgvMainView removeFromSuperview];
// Now the image will have been loaded and decoded and is ready to rock for the main thread
dispatch_sync(dispatch_get_main_queue(), ^{
imgvMainView =[[UIImageView alloc] initWithFrame:CGRectMake(34,41,177,124)];
[cell addSubview:imgvMainView];
[imgvMainView setImage:image];
imgvMainView.contentMode = UIViewContentModeScaleAspectFit;
});
});
Problem is, when i scroll collection view some images are overlapped on one another. Please tell me solution to avoid it.
Thanks in advance.
Please use below line I hope this would work what I am assuming problem of duplicate cell.
UIImageView* imgvMainView =[[UIImageView alloc] initWithFrame:CGRectMake(34,41,177,124)];
[cell.contentView addSubview:imgvMainView];
This is most likely happening because you are reusing cells (correctly) and that the previous use of the cell is still calling the previous image. You must cancel the async task when the cell goes out of view. By the way, it will make you life much easier to use AFNetworking+UIImageView to do this.
One other option is to check that there is no UIimageView in your cell before you create one.
dispatch_sync(dispatch_get_main_queue(), ^{
UIView *viewToRemove;
for (UIView *view in cell.subViews) {
if (view isKingOfClass:UIImageView){
viewToRemove = view;
}
}
[viewToRemove removeFromSuperView];
imgvMainView =[[UIImageView alloc] initWithFrame:CGRectMake(34,41,177,124)];
[cell addSubview:imgvMainView];
[imgvMainView setImage:image];
imgvMainView.contentMode = UIViewContentModeScaleAspectFit;
});
In my application I have used custom tableviewcell for loading two images in one cell, my problem is when I am loading that images on my view first time, it show swaped images (1st image in 2nd image and 2nd in 1st) and then after fraction of seconds it loads proper images (1st in 1st and 2nd in 2nd image). I am using AsyncImageView Class for display image.
Every first time view load it shows wrong and then after correct every time.
In CellForRow
AsyncImageView *imageView = [[AsyncImageView alloc] initWithFrame:celllookAlik.btnFullImg.frame];
imageView.contentMode = UIViewContentModeScaleAspectFill;
imageView.clipsToBounds = YES;
imageView.tag = IMAGE_VIEW_TAG1;
[celllookAlik addSubview:imageView];
AsyncImageView *imageViewll = [[AsyncImageView alloc] initWithFrame:celllookAlik.lookAlikeImage.frame];
imageViewll.contentMode = UIViewContentModeScaleAspectFill;
imageViewll.clipsToBounds = YES;
imageViewll.tag = IMAGE_VIEW_TAG2;
[celllookAlik addSubview:imageViewll];
Display Image in cell using below code:
NSString * imageImage = #"";
imageImage = [[self.arrayResponseLookAlike objectAtIndex:indexPath.row] objectForKey:#"ImagePath"];
AsyncImageView *imageViewCelebrity = (AsyncImageView *)[celllookAlik viewWithTag:IMAGE_VIEW_TAG1];
//cancel loading previous image for cell
[[AsyncImageLoader sharedLoader] cancelLoadingImagesForTarget:imageViewCelebrity];
//load the image
imageViewCelebrity.imageURL = [NSURL URLWithString:[NSString stringWithFormat:#"%#",imageImage]];
NSString * imageImageceleb = #"";
imageImageceleb = [[self.arrayResponseLookAlike objectAtIndex:indexPath.row ] objectForKey:#"LookLikeImage"];
AsyncImageView *imageViewllTemp = (AsyncImageView *)[celllookAlik viewWithTag:IMAGE_VIEW_TAG2];
//cancel loading previous image for cell
[[AsyncImageLoader sharedLoader] cancelLoadingImagesForTarget:imageViewllTemp];
//load the image
imageViewll.imageURL = [NSURL URLWithString:[NSString stringWithFormat:#"%#",imageImageceleb]];
I have suffered with this type of problem, i have used SDWebImage.frameword.
This framework integration is very easy, and it will load the images properly.
For this first we need to create UIImageView in place of AsyncImageView.
Display Image in cell using below code:
[mMainImgView setImageWithURL:[NSURL URLWithString:loImgurl] placeholderImage:[UIImage imageNamed:#"placeholder"]];
for remaining details check with https://github.com/rs/SDWebImage
Can anyone tell me what is wrong with my code. It seems to work but when I scroll fast and then stop, the UIImageView cycles through a few pictures before displaying the correct one. This happens quickly but noticeable.
if (![post objectForKey:#"photoData"] && ![post objectForKey:#"isDownloadingPhoto"]){
cell.instagramPhoto.image = nil;
[[combinedArray objectAtIndex:indexPath.row] setObject:#"loading" forKey:#"photoData"];
[[combinedArray objectAtIndex:indexPath.row] setObject:#"yes" forKey:#"isDownloadingPhoto"];
[cell.instagramPhoto setAlpha:0];
if (instagramURL != nil){
dispatch_async(kBgQueue, ^{
int index = indexPath.row;
NSData* data = [NSData dataWithContentsOfURL: instagramURL];
if (data.length > 0){
[[combinedArray objectAtIndex:index] setObject:data forKey:#"photoData"];
[[combinedArray objectAtIndex:index] setObject:#"no" forKey:#"isDownloadingPhoto"];
UIImage *image = [UIImage imageWithData:data];
dispatch_sync(dispatch_get_main_queue(), ^{
cell.instagramPhoto.image = image;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationBeginsFromCurrentState:YES];
[UIView setAnimationDuration:0.4f];
cell.instagramPhoto.alpha = 1.0;
[UIView commitAnimations];
});
}
});
}
}
else if ([[post valueForKey:#"isDownloadingPhoto"] isEqualToString:#"yes"]) {
NSLog(#"loading");
cell.instagramPhoto.image = nil;
}
else {
NSData *data = [post valueForKey:#"photoData"];
NSLog(#"saved");
UIImage *image = [UIImage imageWithData:data];
cell.instagramPhoto.image = image;
}
Looks like this code is executed inside tableView:cellForRowAtIndexPath. And if you have any cell reusing logic here - you might have problems when cell will be reused before current async image download operation to this cell is complete.
You need to be able to abort these download tasks if cell is being reused before they complete.
** UPDATE **
There are couple ways you can implement it:
The easiest one (and probably most memory-consuming) - make sure you're generating unique cellId for each cell, so there will not be any reuse of already allocated cells. It will be slower, but you will have guarantee that operation you started will finish on the same cell you started it.
Check that cell is the same after your download is complete. You can for example at the beginning of your code assign tag for the cell to its row number.
cell.tag = indexPath.row
Then save it off before starting dataWithContext call and check after.
int oldTag = cell.tag;
dataWithContext...
if (cell.tag != oldTag) {
// Don't so any image update
}
Change dataWithContext to something async so you can actually break and abort the download process. I'm not sure how to proceed with this one - it will require a bit more of research.
I have table with Images cell. Images download from internet and save in local disk. Count = 200. Tableview show this images. When scroll content to bottom, comes message memory warning... Used memory 250 - 300 mb O_O!!! Links to images that do not keep.
NSString *cellID = #"cellId";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID];
...
NSString* imagePath = [arrayContent objectAtIndex:indexPath.row];
UIImage* image = [[UIImage alloc] initWithContentsOfFile:imagePath];
[cell.imageView setImage:image];
Why hide images not release?
Replace this line
UIImage* image = [[UIImage alloc] initWithContentsOfFile:imagePath];
with this and check once
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
Well I used a custom MSAsyncImageCell class that replaces its image when reused by iOS. It loads the image from a URL asynchronously, displaying a "loading" image gracefully and release memory when reused for another image. If you want I can post the code here but the code is a bit long.
Here is the part of code that actually loads the image. I have images off web/caches so it is NSData.
- (BOOL)_loadImageWithData:(NSData *)imageData
{
UIImage *image = [UIImage imageWithData:imageData];
// Just in case loading failed.
if (image)
{
// Extra check - don't mix up.
if ([[self.currentURL absoluteString] isEqualToString:[self.imageURL absoluteString]])
self.asyncImageView.image = image;
return YES;
}
return NO;
}
I am trying to asynchronously load an image in a UITableVIew.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
UITableViewCell *cell = nil;
NSString *cellIndetify = [NSString stringWithFormat:#"cell%d",tableView.tag -TABLEVIEWTAG];
cell = [tableView dequeueReusableCellWithIdentifier:cellIndetify];
IndexPath *_indextPath = [IndexPath initWithRow:indexPath.row withColumn:tableView.tag - TABLEVIEWTAG];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIndetify];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.contentView.backgroundColor = [UIColor blackColor];
// here I init cell image view
UIView *cellSub = [self.waterFlowViewDatasource waterFlowView:self cellForRowAtIndexPath:_indextPath];
cellSub.backgroundColor = [UIColor blackColor];
[cell.contentView addSubview:cellSub];
cellSub.tag = CELLSUBVIEWTAG;
}
// fill image info
[self.waterFlowViewDatasource waterFlowView:self fillDataIntoCellSubview:[cell viewWithTag:CELLSUBVIEWTAG] withIndexPath:_indextPath];
CGFloat cellHeight = [self.waterFlowViewDelegate waterFlowView:self heightForRowAtIndexPath:_indextPath];
CGRect cellRect = CGRectMake(0, 0, _cellWidth, cellHeight);
[[cell viewWithTag:CELLSUBVIEWTAG] setFrame:cellRect];
[self.waterFlowViewDatasource waterFlowView:self relayoutCellSubview:[cell viewWithTag:CELLSUBVIEWTAG] withIndexPath:_indextPath];
return cell;
}
in that ImageView class I init:
(id)initWithIdentifier:(NSString *)indentifier
{
if(self = [super initWithIdentifier:indentifier])
{
self.backgroundColor = [UIColor blackColor];
if (!self.imageView) {
_imageView = [[UIImageView alloc] init];
self.imageView.backgroundColor = IMAGEVIEWBG;
[self addSubview:self.imageView];
self.imageView.layer.borderWidth = 1;
self.imageView.layer.borderColor = [[UIColor colorWithRed:0.85 green:0.85 blue:0.85 alpha:1.0] CGColor];
}
......some others controllers
}
-(void)setImageWithURL:(NSURL *)imageUrl{
UIImage *cachedImage = [[SDImageCache sharedImageCache] imageFromKey:[imageUrl absoluteString]];
if (cachedImage) {
self.imageView.image = cachedImage;
}else{
SDWebImageManager *manager = [SDWebImageManager sharedManager];
[manager downloadWithURL:imageUrl delegate:self options:SDWebImageCacheMemoryOnly userInfo:[[NSDictionary alloc] initWithObjectsAndKeys:[imageUrl absoluteString], #"image_url", [NSValue valueWithBytes:&imageSize objCType:#encode(CGSize)], #"image_size", [NSNumber numberWithInt:arrIndex], #"imageview_index", nil]];
_imageView.image = [UIImage imageNamed:#"album_detail_placeholder.png"];
}
.....
.....
- (void)imageDecoder:(SDWebImageDecoder *)decoder didFinishDecodingImage:(UIImage *)image userInfo:(NSDictionary *)userInfo {
imageView.image = image
}
As you see here I used SDWebImageManager, but that doesn't seem to be the problem.
When pull up to next page, before the next page's images have loaded, if I scroll back to previous page's loaded image, the image will be covered by another image (which is should display in the newest page, not current page...) (for example, in the first page, I have a image and there is cat in this image, and then I scroll down till pull up to request next page, and after get all next page image's url, start asynchronous thread download images, before the newest images downloaded, scroll back to top, maybe first page. After awhile, some images downloaded, they should display in there cell, but now the images will cover the current page images, maybe the cat image now have a dog image on it) what shall I do?
When a row is scrolled off-screen, the table view reuses that row's cell for another row that has scrolled on-screen.
The problem is that you are using the ImageView as the delegate of the background loader, and the ImageView is associated with a cell, not a row. By the time the background loader finishes loading the image, the cell may have been reused for another row.
You need to make the table view's data source be the delegate for the background image loader. It should put the index path of the row into the userInfo dictionary when it calls downloadWithURL:delegate:options:userInfo:. When the downloader sends imageDecoder:didFinishDecodingImage:userInfo: to the data source, the data source should get the index path out of the userInfo and use it to ask the table view for the cell currently displaying that row (by sending cellForRowAtIndexPath: to the table view).