Objective C UI Collection issue - objective-c

Description :-
Hello , When we are running this code when is cell relocate image is changing on scrolling.
Please let me know how to fix.
- (UICollectionViewCell )collectionView:(UICollectionView )collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"Cellidentifier";
CollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
NSString * string = [_temp objectAtIndex:indexPath.row];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// retrive image on global queue
UIImage * img = [UIImage imageWithData:[NSData dataWithContentsOfURL: [NSURL URLWithString:string]]];
dispatch_async(dispatch_get_main_queue(), ^{
cell.imageView.image = img;
});
});
return cell;
}

The problem here is that if the cells get reused the previous image might still be loading or be set. You can override the cell's prepareForReuse to nil the image. For asynchronous loading of images you should check if the cell's model object is stil the same as when you started the loading, if not, then don't set the image as it arrived too late.

Related

Loading url image array add to UIcollectionview

I want to load images array from Url and add to UICollectionView
Tony.pageImages =imagearray;
[Tony reloadData];
NSLog(#"imagearray%#",imagearray);
Tony is Collection view.h/m files. pageImages is NSMutableArray on the Tony.h files. The Image array display console log mean i got image array correctly
Those are Url.
but when i add code on the UICollectionView method it doesn't work
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell =
[collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
UIImageView *CollectionViewImage = (UIImageView *)[cell viewWithTag:120];
CollectionViewImage.image= [UIImage imageNamed:self.pageImages[indexPath.row]];
return cell;
}
Do i miss something ?
This is my imagearray
imagearray = [[NSMutableArray alloc]init];
for (int i = 0;i < comment.count; i++)
{
[imagearray addObject:comment[i][#"pic_url"]] ;
}
You have to implement and set the following dataSource delegate UICollectionViewDataSource in your viewcontroller:
- (NSInteger)numberOfSectionsInCollectionView:(UICollectionView *)collectionView {
return 1;
}
- (NSInteger)collectionView:(UICollectionView *)collectionView
numberOfItemsInSection:(NSInteger)section {
return imagearray.count;
}
If I got it right, you need to load image from URL.
To do that simply add this code:
[CollectionViewImage.image setImageWithURL:[NSURL URLWithString:self.pageImages[indexPath.row]] placeholderImage:nil];
Or if you want to add placeholder image, just set placeholderImage:[UIImage imageNamed:#"someImageInYourAssets"];
NSData * imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString:self.pageImages[indexPath.row]]];
UIImage *image = [UIImage imageWithData: imageData];
CollectionViewImage.image = image;
This is solution how solve problem loading image from url,without addition frameworks such as "Heneke","AFNetworking"..etc..In Objective C Image View can't communicated with URL directly, but can using NSData as Helper Object(wrapper).

table view with images which are loaded from server in iphone

Hi I am developing IOS application. My application contains table view with image as part of my table. I am loading my image from server. It is working fine. But problem with my table view is once I scroll my table view it is start flickering my images. That mean it showing wrong image for some time after some time it shows right images. this behaviour continues when I scroll. Is there any need to explicitly call any object to nil or release some cell object or holding some cell objects. My cell for table view looks like :
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"MediaContentCell";
MediaContentCell *cell = (MediaContentCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil) {
cell = (MediaContentCell *)[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
}
VideoDataModel *videoData = [_mediaContentArray objectAtIndex:indexPath.row];
cell.mediaTitle.text = videoData.title;
cell.mediaSubtitle.text = videoData.shortdescription;
NSMutableArray *posters = videoData.poster;
dispatch_queue_t myQueue = dispatch_queue_create("ImageQue",NULL);
dispatch_async(myQueue, ^
{
UIImage *image;
if(!posters)
{
image = [UIImage imageNamed:#"dummyprog_large1.png"];
}
else
{
for(int index = 0 ; index < posters.count; index++)
{
PosterDataModel *posterData = [posters objectAtIndex:index];
if([posterData.postertype isEqualToString:POSTER_TYPE_LANDSCAPE])
{
image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:posterData.posterurl]]];
break;
}
}
}
dispatch_async(dispatch_get_main_queue(), ^
{
cell.mediaPicture.image = image;
});
});
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
return cell;
}
Is there any one can help me for this? Need some help Thank you.
use - SDWebImage
[cell.imageView sd_cancelCurrentImageLoad];
[cell.imageView setImageWithURL:[NSURL URLWithString:#"http://www.domain.com/path/to/image.jpg"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
I am using this framework and Its working fine for me.
cell.imageView.image = [UIImage imageWithData:yourDefaultImgUrl];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *imageData = [NSData dataWithContentsOfURL:yourServerImageUrl];
if (imageData){
dispatch_async(dispatch_get_main_queue(), ^{
UITableViewCell *updateCell = [tableView cellForRowAtIndexPath:indexPath];
if (updateCell)
updateCell.imageView.image = [UIImage imageWithData:imageData];
});
}
});
It helps you :)
It's the reuse mechanism that causes your problem
Say, if your table view has 1000 cells to display, and 5 cells are visible on the screen at a time, iOS will only create 6 UITableViewCell objects in the memory.
In your code, the image will be loaded asynchronously from the network, and then set to the [mediaPicture] belonging to the cell at an index path, but when you scroll the table view, because of the reuse mechanism, the [cell.mediaPicture] might not be correctly related to the index path anymore, and the downloaded image will be wrongly set.
You can take a look at this question about the reuse mechanism:
UITableViewCell - Understanding "reuseable"
And Amol's answer is exactly the solution for your case.

Asynchronous loading image inside uitableviewcell

Hello I am trying to use EGOImageView inside a CustomTableViewCell who i made to customize the cell. This is the code where I used the EGOImageView.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString* simpleTableIdentifier = #"Albums";
CustomTableCell* cell = (CustomTableCell*)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (!cell)
{
cell = [[CustomTableCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:simpleTableIdentifier];
NSLog(#"Show once or more times");
}
NSDictionary* dictionary = (NSDictionary*)[self.albumCollection objectAtIndex:indexPath.row];
cell.label.text = [dictionary valueForKey:#"name"];
EGOImageView* imageView = [[EGOImageView alloc] initWithPlaceholderImage:[UIImage imageWithContentsOfFile:#""]];
[imageView setImageURL:[NSURL URLWithString:[NSString stringWithFormat:#"https://graph.facebook.com/%#/picture?type=small&access_token=%#", (NSString*)[dictionary valueForKey:#"id"], [[FBSession activeSession] accessToken]]]];
[imageView setFrame:CGRectMake(0.0f,0.0f,78.0f,78.0f )];
[cell.iView addSubview:imageView];
[imageView release];
The image on each cell loading the same image. Would it be because it reused the cell while loading the image.
I found a problem I can't think of why the problem happened. I used the graph api to grab the image https://graph.facebook.com/%#/picture?type=small&access_token=%# where the first parameter was the album id.
To make myself easy to see the problem I only used one album on the cell, no matter what album i used the same photo turned up. But when I copy the link to the browser, the actual photo url shown on the address bar with the image shown and it shown the correct photos.
Does anyone know what was wrong.
Here is example. It loads user pics from some server in background and updates cell image. Note that imageView.image is set to nil at the beginning. This is dome for the case of cell reuse so that you will have no image rather than wrong image for the time while its downloading.
One more thing to add is that, would be also good to have a cache so that it does not download images all the time. Another nice thing is to not download images in edge networks.
- (UITableViewCell *)tableView:(UITableView *)_tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"TransactionCell";
NSMutableArray *data = searching ? searchResult : dataSource;
NSDictionary *object = [data objectAtIndex:[indexPath row]];
UITableViewCell *cell = [_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithIdentifier:CellIdentifier] autorelease];
}
cell.imageView.image = nil;
cell.textLabel.text = #"Your cell text";
NSString *contact = #"foo#gmail.com";
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData *imgData = [appDelegate addUserPic:contact];
if (imgData == nil && netStatus == ReachableViaWiFi) {
NSString *url = [NSString stringWithFormat:#"http://somehost.com/userpic/%#", contact];
imgData = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
}
dispatch_async(dispatch_get_main_queue(), ^{
UITableViewCell *updateCell = [self.tableView cellForRowAtIndexPath:indexPath];
if (updateCell) {
if (imgData) {
[appDelegate setUserPic:contact imgData:imgData];
updateCell.imageView.image = [UIImage imageWithData:imgData];
} else {
updateCell.imageView.image = nil;
}
/* This forces the cell to show image as now
it has normal bounds */
[updateCell setNeedsLayout];
}
});
});
return cell;
}

GCD UITableView asynchronous load images, wrong cells are loaded until new image download

I have a UITableView with custom cells. I load images asynchronously using Grand Central Dispatch. Everything works fine, but when I scroll down, previously loaded images are shown till the new image is downloaded. Here is my code:
if (![[NSFileManager defaultManager] fileExistsAtPath:[path stringByAppendingPathComponent:#"image.png"]])
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSString *url=[pat stringByAppendingPathComponent:#"comments.txt"];
NSString *u=[NSString stringWithContentsOfFile:url encoding:NSUTF8StringEncoding error:nil];
NSURL *imageURL=[NSURL URLWithString:u];
NSData *image=[NSData dataWithContentsOfURL:imageURL];
[image writeToFile:[pat stringByAppendingPathComponent:#"image.png"] atomically:YES];
dispatch_sync(dispatch_get_main_queue(), ^{
cell.imageView.image=[UIImage imageWithContentsOfFile:[pat stringByAppendingPathComponent:#"image.png"]];
[cell setNeedsLayout];
NSLog(#"Download");
});
});
}
else
{
NSLog(#"cache");
cell.imageView.image=[UIImage imageWithContentsOfFile:[pat stringByAppendingPathComponent:#"image.png"]];
}
Any suggestions appreciated.
P.S. I reuse the cells
Rather than capturing the cell you need to capture the index path, then get the cell back using:
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
That way, if the cell is now off screen you'll get nil back and the image won't be set on the wrong cell.
The other thing you need to add after your dispatch_async() is a cell.imageView.image=somePlaceholderImage.
E.g.:
if (![[NSFileManager defaultManager] fileExistsAtPath:[path stringByAppendingPathComponent:#"image.png"]])
{
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSString *url=[pat stringByAppendingPathComponent:#"comments.txt"];
NSString *u=[NSString stringWithContentsOfFile:url encoding:NSUTF8StringEncoding error:nil];
NSURL *imageURL=[NSURL URLWithString:u];
NSData *image=[NSData dataWithContentsOfURL:imageURL];
[image writeToFile:[pat stringByAppendingPathComponent:#"image.png"] atomically:YES];
dispatch_sync(dispatch_get_main_queue(), ^{
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.imageView.image=[UIImage imageWithContentsOfFile:[pat stringByAppendingPathComponent:#"image.png"]];
[cell setNeedsLayout];
NSLog(#"Download");
});
});
cell.imageView.image=[UIImage imageNamed:#"placeholder"];
}
else
{
NSLog(#"cache");
cell.imageView.image=[UIImage imageWithContentsOfFile:[pat stringByAppendingPathComponent:#"image.png"]];
}
In your - (void)tableView:(UITableView *)aTableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath { You need to clear out the image, or reset it to your spinner. Since table view rows are reused, this is the behavior you will see.
Doesn't UITableViewCell define -(void) prepareForReuse for that purpose?
Override it and clear your imageView in there.

dequeueReusableCellWithIdentifier causing problem on UIImageView

I am loading a tableView with 500 rows. The problem is that in each row there is a different picture. Or when I use dequeueReusableCellWithIdentifier, those picture are just loaded again and the real pictures I am looking for are not shown (I just have about 8 different pictures : the first 8 loaded on my screen). If I don't use the dequeureReusableCellIdentifier, all the picture are loaded. But will it slow the displaying ?
Here is the code (I am currently working on getting the picture cached) :
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CustomCellIdentifier = #"CustomCellIdentifier";
UITableViewCell *cell = [tableView
dequeueReusableCellWithIdentifier: CustomCellIdentifier];
NSLog(#"Launching CellForRowAtIndexPath");
if (cell == nil) {
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"CustomCell"
owner:self options:nil];
if ([nib count] > 0) {
cell = self.profilCell;
} else {
NSLog(#"failed to load CustomCell nib file!");
}
}
NSUInteger row = [indexPath row];
NSDictionary *rowData = [listProfils objectAtIndex:row];
UILabel *nameLabel = (UILabel *)[cell viewWithTag:nameValueTag];
nameLabel.text = [rowData objectForKey:#"name"];
NSString *finalId = [NSString stringWithFormat:#"http://graph.facebook.com/%#/picture", [rowData objectForKey:#"id"]];
UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:finalId]]];
[profilPic setImage:image];
return cell;
}
THank you ! :)
It looks like you have an ivar profilPic that is probably an outlet that gets linked when you load a new cell nib. If that's the case, it's always going to point to the last cell that you loaded and won't change the image in the cell you've just dequeued. Instead of using an outlet, you might want to identify that custom view some other way, like a tag. So, if you set the profile pic UIImageView's tag to 100, for example, in Interface Builder, you could do something like this:
UIImage *image = [[UIImage alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:finalId]]];
UIImageView* cellImageView = (UIImageView*)[cell viewWithTag:100];
[cellImageView setImage:image];
Also, I just want to point out that -dataWithContentsOfURL: will load the URL synchronously on the main thread. If you're testing in the simulator on a fast connection, this will work pretty well. If, however, you are on 3G in SoHo on Friday afternoon... your app will probably start being killed by the watchdog.
I just met this problem, my solution is hold a private NSMutableDictionary to store the new images which asynchronously loaded from web before, use my identifier as key, UIImageView as Object (because I need to load the icon image first), when web image is ready, change it, When tableView dequeue return's null, I can read the original UIImage from my own cache.
Something like this.
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
UIImageView *imageView = [thumbnailCache objectForKey:identifier];
if (!imageView) {
cell.imageView.image = [UIImage imageNamed:#"icon.png"];
[thumbnailCache setObject:cell.imageView forKey:identifier];
} else {
cell.imageView.image = imageView.image;
}
}
When I load the actual image from web, refresh the thumbnail cache.
asynchronously_load_image_from_web(^(UIImage *image) {
cell.imageView.image = image;
[thumbnailCache setObject:cell.imageView forKey:identifier];
});