IOS: Collection view image position changing - iphone

I'm using UICollectionView to display images which are loading from the device photo gallery. I'm using Asset Library to load the images. When I'm scrolling the UICollectionView, images are changing their positions inside the collection view (not duplicating). Therefore when I clicked on an image, different image is loading. Any help?
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *identifier = #"Cell";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
UIImageView *GalleryImageView = (UIImageView *)[cell viewWithTag:100];
url=#"";
Document* doc = [galleryImages objectAtIndex:indexPath.row];
GalleryImageView.contentMode = UIViewContentModeScaleAspectFill;
url = doc.path;
NSLog(#"%#",url);
NSURL *referenceURL = [NSURL URLWithString:url];
__block UIImage *returnValue = nil;
[library assetForURL:referenceURL resultBlock:^(ALAsset *asset)
{
returnValue = [UIImage imageWithCGImage:[[asset defaultRepresentation] fullScreenImage]];
GalleryImageView.image = returnValue;
returnValue = nil;
documentID= [dbutil getDocumentIDbyPath:url];
GalleryImageView.tag = documentID;
}
failureBlock:^(NSError *error)
{
NSLog(#"error : %#", error);
}];
return cell;
}

Related

Set UITableview cell image from url in iOS

I am setting image on UITableViewCell using image url ,but the images doesn't get load unless i scrolls the UITableView.Here is the code that i have been using,i got to know about SDWeb Image library to download images from url,but i does;t want to use any library.Please tell me what aim doing wrong in this.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
// Configure the cell...
NSDictionary *dictCard=[cardsDetailsArray objectAtIndex:indexPath.row];
UILabel *nameLabel = (UILabel *)[cell viewWithTag:10];
UILabel *dateLabel = (UILabel *)[cell viewWithTag:11];
UIImageView *cellImage=(UIImageView *)[cell viewWithTag:0];
CGSize firstSize=CGSizeZero;
if([[dictCard objectForKey:#"orientation"]isEqualToString:#"1"]){
[cellImage setFrame:CGRectMake(0, 0, 75, 68)];
firstSize=CGSizeMake(75,68);
}
if([[dictCard objectForKey:#"orientation"]isEqualToString:#"0"]){
[cellImage setFrame:CGRectMake(0, 0, 107, 72)];
firstSize=CGSizeMake(107,72);
}
[cellImage setBackgroundColor:[UIColor clearColor]];
NSString *string=[dictCard objectForKey:#"email_sent"];
NSArray *items = [string componentsSeparatedByString:#","];
dateLabel.text=[dictCard objectForKey:#"date"];
nameLabel.text=[NSString stringWithFormat:#"Sent to %d People",[items count]];
NSURL* url = [NSURL URLWithString:(NSString *) [dictCard objectForKey:#"card_thumbnail"]];
NSURLRequest* request = [NSURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse * response,
NSData * data,
NSError * error) {
if (!error){
UIImage* image = [[UIImage alloc] initWithData:data];
//i am scaling the image here
UIImage *imageScale=[self imageWithImage:image scaledToSize:firstSize];
[cellImage setImage:imageScale];
}
}];
return cell;
}
I have also added [__tableViewDraft reloadData];after setting the cell image but due to this my cell keeps on changing its cell image.
Once the image has been downloaded, you need to ask iOS to refresh the cell. Check out reloadRowsAtIndexPaths:withRowAnimation:, among others.
Typically you might have have cells backed by CoreData objects and download and save the image to the managed object. You'd then have an NSFetchedResultsControllerDelegate trigger an update when the managed object changes, refreshing the row.

uicollection view reusable cell images are reloading while scrolling

hello am using UICollectionView for showing images in my iphone application but when i scrolling the view the loaded images are gone and loading images again this is because of "dequeueReusableCellWithReuseIdentifier"
and this is my code
static NSString * const kCellReuseIdentifier = #"collectionViewCell";
[self.collectionViewPack registerNib:[UINib nibWithNibName:#"CollectionViewItem" bundle:nil] forCellWithReuseIdentifier:kCellReuseIdentifier];
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCellReuseIdentifier forIndexPath:indexPath];
cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
UILabel *titleLabel = (UILabel *)[cell viewWithTag:100];
UIImageView *icon=(UIImageView *)[cell viewWithTag:101];
// [titleLabel setText:[NSString stringWithFormat:#"%d",indexPath.row]];
[titleLabel setText:[NSString stringWithFormat:#"%#",[arrayImages objectAtIndex:indexPath.row]]];
icon.image =[UIImage imageNamed:#"loading-1.png"];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSString *imagePath = [NSString stringWithFormat:#"%#", [test.arrImages objectAtIndex:indexPath.row]];
NSURL *imageUrl = [NSURL URLWithString:imagePath];
NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
UIImage *image = nil;
if (imageData){
image = [[UIImage alloc] initWithData:imageData];
icon.image = image;
}
[image release];
});
return cell;
}
please help me out from this.
I guess you need to add some image cache to your code, I recommend you to use AFNetworking,
you can easily do:
import "UIImageView+AFNetworking.h"
......
[cell.imageView setImageWithURL:imageUrl placeholderImage:[UIImage imageNamed:#"default"]];
And, it has an internal Cache that will help :D
and for your code... try by adding this in your block
dispatch_async(dispatch_get_main_queue(), ^{
icon.image = image;
});
change kCellReuseIdentifier to dynamic
static NSString * const kCellReuseIdentifier = #"collectionViewCell";
to
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath {
NSString * kCellReuseIdentifier =
[NSString stringWithFormat:#"collectionViewCell%d",indexPath.row];
It may work
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView
cellForItemAtIndexPath:(NSIndexPath *)indexPath {
// Setup cell identifier
static NSString *cellIdentifier = #"put you viewController here";
/* this block to use nib-based cells */
UICollectionViewCell *cell =
[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier
forIndexPath:indexPath];
/* end of nib-based cell block */
/* this block to use subclass-based cells */
yourviewController *cell =
(CVCell *)[collectionView dequeueReusableCellWithReuseIdentifier:cellIdentifier
forIndexPath:indexPath];

Application Crash on Fast switching between UISegment

I have a segment and a table view, I have to reload the data in the table view its working but when i switch the segment buttons fast then application crashes.
On segment i have three buttons and on their action I am triggering a request to a url and fetching the json from that url (3 different urls resp. and returns 10, 17 and 8 results in json).
I have a custom table cell which have the images in it and i am trying to lazily load theose images.
In JSON result each object of json have various keys in it like name, id, imageurl etc.
the id is unique throughout the application and I am trying to load the images and save the images in local memory based on that unique id, so that i can show the cashed images and no need to redownload the images on segment change because some enteries on all three segments are same.
Here is my complete code
- (IBAction)segmentedControlIndexChanged {
NSString *offerRequestUrl = nil;
switch (self.mySegment.selectedSegmentIndex) {
case 0:
offerRequestUrl = #"url_one";
self.feedRequestUrl = [NSURL URLWithString:offerRequestUrl];
break;
case 1:
offerRequestUrl = #"url_two";;
self.feedRequestUrl = [NSURL URLWithString:offerRequestUrl];
break;
case 2:
offerRequestUrl = #"url_three";;
self.feedRequestUrl = [NSURL URLWithString:offerRequestUrl];
break;
default:
break;
}
[self parseJSONWithURL:self.feedRequestUrl];
}
- (void) parseJSONWithURL:(NSURL *) jsonURL
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSData* data = [NSData dataWithContentsOfURL: jsonURL];
[self performSelectorOnMainThread:#selector(fetchedData:) withObject:data waitUntilDone:YES];
});
}
- (void)fetchedData:(NSData *)responseData {
//parse out the json data
NSError* error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:responseData
options:kNilOptions
error:&error];
self.feedsArray = [json objectForKey:#"result"];
[self.myTableView reloadData];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
int count = self.feedsArray.count;
// if there's no data yet, return enough rows to fill the screen
if (count == 0)
{
return 1;
}
return count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// customize the appearance of table view cells
//
static NSString *CellIdentifier = #"MyTableCell";
static NSString *PlaceholderCellIdentifier = #"PlaceholderCell";
// add a placeholder cell while waiting on table data
int nodeCount = [self.feedsArray count];
if (nodeCount == 0 && indexPath.row == 0)
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:PlaceholderCellIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle
reuseIdentifier:PlaceholderCellIdentifier];
cell.detailTextLabel.textAlignment = UITextAlignmentCenter;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
cell.detailTextLabel.text = #"Loading . . .";
[self performSelector:#selector(checkAndDisplayAlert) withObject:self afterDelay:10.0];
return cell;
}
CustomCell *cell = (CustomCell*)[tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (nodeCount > 0)
{
// Configure the cell...
cell.carImageView.image = [UIImage imageNamed:#"Placeholder"]; //acts as default image
if([self.imageDict valueForKey:[NSString stringWithFormat:#"%#", self.feedsArray[indexPath.row][#"id_str"]]]==nil)
{
[NSThread detachNewThreadSelector:#selector(displayingSmallImage:) toTarget:self withObject:indexPath];
} else {
cell.carImageView.image = [self.imageDict valueForKey:[NSString stringWithFormat:#"%#", self.feedsArray[indexPath.row][#"id_str"]]];
}
cell.imageView.clipsToBounds = YES;
cell.titleLabel.text = self.feedsArray[indexPath.row][#"title_key"];
}
return cell;
}
- (void) displayingSmallImage:(NSIndexPath *)indexPath
{
NSString *imageUrl = self.feedsArray[indexPath.row][#"icon_url"];
NSURL *url = [NSURL URLWithString:imageUrl];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
if(image == nil)
{
image = [UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Placeholder"]];
}
[self.imageDict setObject:image forKey:[NSString stringWithFormat:#"%#", self.feedsArray[indexPath.row][#"id_str"]]];
[self performSelectorOnMainThread:#selector(imageReceived:) withObject:indexPath waitUntilDone:NO];
}
- (void) imageReceived:(NSIndexPath *)indexPath
{
UIImage *image = (UIImage *)[self.imageDict objectForKey: [NSString stringWithFormat:#"%#", self.feedsArray[indexPath.row][#"id_str"]]];
UIImageView *imgs = (UIImageView *)[[self.myTableView cellForRowAtIndexPath:indexPath] viewWithTag:IMG_TAG];
[imgs setImage:image];
[self.myTableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
- (void) checkAndDisplayAlert
{
if (!self.feedsArray && self.isAlertPresent == NO) {
UIAlertView *nilAlert = [[UIAlertView alloc] initWithTitle:#"Sorry!"
message:#"No result returned from server."
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[nilAlert setTag:kNilAlertTag];
self.isAlertPresent = YES;
[nilAlert show];
}
}
The main things I have to do is
lazily download the images
cache the images in local memory based on unique ID
Check the cashed images dictionary for already downloaded image and display it
If possible save these downloaded images in the local memory (nsuserdefaults etc) so that if user restart the app then also images are there and can be displayed based on their unique ID and no need to download again.
Any help would be appreciated.
Please post the error log, if it is array out of bounds exception I suspect these two methods
- (void)fetchedData:(NSData *)responseData & your tableViewDatasource
To find which line of code causes this crash do this. Go to break points tab on the left side and click + in the bottom.
Then you would get something like this:
Just hit done, run your code again and tell us which line caused the exception.
I understood your problem, why do you want to take the URL from the array in this function
- (void) displayingSmallImage:(NSIndexPath *)indexPath
you could pass the Url to load to that function, from cellForRowAtIndex like this:
NSArray *argsToPass=[NSArray arrayWithObjects:indexPath,self.feedsArray[indexPath.row][#"icon_url"]];
[NSThread detachNewThreadSelector:#selector(displayingSmallImage:) toTarget:self withObject:argsToPass];
and your function is modified as:
- (void) displayingSmallImage:(NSArray *)args
{
if([args count] == 0)
{
NSString *imageUrl = [args objectAtIndex:1];
NSIndexPath *indexPath=[args objectAtIndex:0];
NSURL *url = [NSURL URLWithString:imageUrl];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:url]];
if(image == nil)
{
image = [UIImage imageWithContentsOfFile:[[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:#"Placeholder"]];
}
[self.imageDict setObject:image forKey:[NSString stringWithFormat:#"%#", self.feedsArray[indexPath.row][#"id_str"]]];
[self performSelectorOnMainThread:#selector(imageReceived:) withObject:indexPath waitUntilDone:NO];
}
}
you can set self.view.userInteractionEnabled=NO when you are sending request to server.
and when u get the data just enable the user interaction .so that multiple requests are avoided.

Wrong images are showing up in UITableviewcell

I am using GCD to load images from web into my UITableViewCell. But, wrong images are showing up.
Here is code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
AppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
UITableViewCell *cell = [self.newsTable dequeueReusableCellWithIdentifier:#"newsTableCell"];
NSString *user = [usernames objectAtIndex:[indexPath row]];
NSString *stat = [statistics objectAtIndex:[indexPath row]];
NSString *imagePath = [appDelegate.URL stringByAppendingString:#"ImageName"];
UIImageView *userImageView = (UIImageView *)[self.view viewWithTag:80];
NSString *imagePath1 = [imagePath stringByAppendingString:[imagepaths objectAtIndex:[indexPath row]]];
NSURL *url = [NSURL URLWithString:imagePath1];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *img = [[UIImage alloc] initWithData:data];
userImageView.layer.cornerRadius = 5.0;
userImageView.layer.masksToBounds = YES;
dispatch_sync(dispatch_get_main_queue(), ^{
[userImageView setImage:img];
});
});
return cell
}
Please let me know, where I am going wrong.
You are not using at all your cell variable, you are setting images on an UIImageView which comes from self.view. The images will never be set correctly on the cells of the table.

Cancel Selector in UITableViewCell

I have scenario that in which i am using selector in TableViewCell as bellow and when I click on back button in my view I want to cancel that selector and I am sending dictionary as object in Selector
My code is as bellow
In Header File
NSMutableDictionary* photoDict;
NSMutableDictionary* dictImages;
In .M file
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
NSString *cellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
if(cell==nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:cellIdentifier];
[[NSBundle mainBundle]loadNibNamed:#"MyCellNib" owner:self options:Nil];
cell = detailChainObj;
}
NSString* avatarURL =#"image_Url"; //Any url of image for cell.
NSString *key =[[NSString alloc] initWithFormat:#"Key%d%d",indexPath.section,indexPath.row];
dictImages = [NSDictionary dictionaryWithObjectsAndKeys:imageViewCell,#"Img",imgURL,#"imgURL",key,#"key", nil];
[self performSelectorInBackground:#selector(DownloadLinkzImageOfUser:) withObject:dictImages];
if([photoDic valueForKey:keyAvt])
{
NSData* data = (NSData*)[photoDic valueForKey:key];
imageViewCell.image = [UIImage imageWithData:data];
}
else
{
[self performSelectorInBackground:#selector(DownloadImagesForCell:) withObject:dictImages];
}
}
//
-(void)DownloadImagesForCell:(NSDictionary *)result
{
UIImageView* img = (UIImageView*)[result objectForKey:#"Img"];
NSString* urlAvt = [result valueForKey:#"imgURL"];
if([urlAvt isEqualToString:#"No Image"])
{
img.image = [UIImage imageNamed:#"noimg.png"];
}
else
{
NSData* data = [NSData dataWithContentsOfURL:[NSURL URLWithString:imgURL]];
img.image = [UIImage imageWithData:data];
[photoDic setValue:data forKey:[NSString stringWithFormat:#"%#",[result valueForKey:#"key"]]];
}
}
Now I want to cancel this selecter when I press back button
and please keep in mind that I have already use
[NSObject cancelPreviousPerformRequestsWithTarget:self selector:#selector(DownloadImagesForCell:) object:dictImages];
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/nsobject_Class/Reference/Reference.html
I guess this method works for performSelector:withObject:afterDelay: only.