UIImage in UICollectionView not showing - ios

For some reason, I can not get my base 64 encoded image to show in a UIImageView in a UICollectionView.
Here is my code:
-(UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"task_cell";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
NSDictionary* json = [dataSource objectAtIndex:indexPath.row];
[cell setBackgroundColor:[UIColor whiteColor]];
UIImageView *image = (UIImageView *)[cell viewWithTag:100];
UILabel *text = (UILabel *)[cell viewWithTag:101];
NSString *ext = [[json objectForKey:#"image"] pathExtension];
NSString *final = [NSString stringWithFormat:#"data:image/%#;base64,%#", ext, [json objectForKey:#"b64img"]];
NSURL *url = [NSURL URLWithString:final];
NSData *imageData = [NSData dataWithContentsOfURL:url];
[image setImage:[UIImage imageWithData:imageData]];
text.text = [json objectForKey:#"title"];
return cell;
}
DEBUG LOG:
Printing description of final:
data:image/jpg;base64,/9j/4AAQSkZJRgABAQEASABIAAD/......(goes on for a while)
url = nil
imageData is nil
I do see the UILabel changing.
So, what should I try.

This is likely an issue with how you construct the path to your image. This looks funky:
NSString *final = [NSString stringWithFormat:#"data:image/%#;base64,%#", ext, [json objectForKey:#"b64img"]];
Please post the NSLog value of final, url and whether or not imageData is nil at time of setting image.

I had to do the following to fix it..
Change the code for the url:
NSURL *url = [NSURL URLWithString:[NSString URLEncodeString:final]];
Add the function URLEncodeString to NSString. I used the code from NSURL URLWithString:myString returns Nil?. It works like a charm.
And presto...it works.

Related

Asynchronous image downloader error Obj-c SDWebimage

Im working in a simple app that shows products in a tableview, i get the data from a json api. the problem is the table get laggy because of synchronous download of the images. im trying to use SDWebimage framework to solve this but i get this error:
"'NSInvalidArgumentException', reason: '-[UIImageView sd_setImageWithURL:placeholderImage:]: unrecognized selector sent to instance "
the code i have is this:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"Cell" forIndexPath:indexPath];
NSDictionary *dictionary = [self.json objectAtIndex:indexPath.row];
cell.textLabel.text=[dictionary objectForKey:#"name"];
cell.detailTextLabel.text = [dictionary objectForKey:#"description"];
//old synchronous code
/* NSString *path = [[[[dictionary objectForKey:#"images"] objectAtIndex:0] valueForKey:#"thumb"] valueForKey:#"url"];
NSString *ruta = [NSString stringWithFormat:#"http://18.221.78.126/ecoferia%#",path];
NSURL *url = [NSURL URLWithString:ruta];
NSData *imgData = [NSData dataWithContentsOfURL:url];
cell.imageView.image = [UIImage imageWithData:imgData];
*/
//trying to do asynchronous download of the images
NSString *path = [[[[dictionary objectForKey:#"images"] objectAtIndex:0] valueForKey:#"thumb"] valueForKey:#"url"];
NSString *ruta = [NSString stringWithFormat:#"http://18.221.78.126/ecoferia%#",path];
[cell.imageView sd_setImageWithURL:[NSURL URLWithString:ruta]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
return cell;
}
also i have the SDWebimage installed in my proyect and imported in the .m file like this:
#import "SDWebImage/UIImageView+WebCache.h"
im super new to objective-c so all the tips are appreciated.
REGARds..
The solution was put $(inherited) in Build Settings -> Other Linker flags.
Working good :)

How to set image path coming from server in uitableviewcell

I am making an app in which i am getting data from server and in data image path is also coming but when i am setting image to my tableview cell app will become too much heavy may b i am not setting image properly below is my sample code thanx in advance :)
(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *tableviewidentifier = #"cell";
tablecellTableViewCell *cell= [self.activitiesTableView_ dequeueReusableCellWithIdentifier:tableviewidentifier];
if(cell==nil)
{
cell = [[tablecellTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:tableviewidentifier];
}if(indexPath.row == [self tableView:tableView numberOfRowsInSection:indexPath.section] - 1){
// [[cell textLabel] setText:#"Load more records"];
}
UILabel *valuedate = (UILabel *)[cell viewWithTag:21];
UILabel *msg = (UILabel *)[cell viewWithTag:22];
UILabel *date = (UILabel *)[cell viewWithTag:23];
UILabel *time = (UILabel *)[cell viewWithTag:24];
valuedate.text=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"offerTitle"];
msg.text=#"How are you?";
NSString *img=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"offerPhoto"];// here i am getting image path
UIImage *img1 = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:img]]];
cell.imageView.image=img1;// here i am setting image due to which app is so heavy and stuck
return cell;
}
Dont use imageWithData: for setting images. It is synchronous and will make your app run slow.
Instead of that Use SDWebImage
You just need to do following things:
Dump SDWebImage folder into your project.
Import UIImageView+WebCache.h.
Set the image using: sd_setImageWithURL:
OR
by GCD (Grand Central Dispatch) and sending asynchronous requests. Code copied from HERE.
First implement following method.
- (void)downloadImageWithURL:(NSURL *)url completionBlock:(void (^)(BOOL succeeded, UIImage *image))completionBlock
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[NSURLConnection sendAsynchronousRequest:request
queue:[NSOperationQueue mainQueue]
completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if ( !error )
{
UIImage *image = [[UIImage alloc] initWithData:data];
completionBlock(YES,image);
} else{
completionBlock(NO,nil);
}
}];
}
and then in your cellForRowAtIndexPath
[self downloadImageWithURL:your_url completionBlock:^(BOOL succeeded, UIImage *image) {
if (succeeded) {
// change the image in the cell
cell.imageView.image = image;
}
}];
try this below code, hope this helps u .
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
__block tablecellTableViewCell *cell= [self.activitiesTableView_ dequeueReusableCellWithIdentifier:tableviewidentifier];
if(cell==nil)
{
cell = [[tablecellTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:tableviewidentifier];
}
if(indexPath.row == [self tableView:tableView numberOfRowsInSection:indexPath.section] - 1)
{
// [[cell textLabel] setText:#"Load more records"];
}
UILabel *valuedate = (UILabel *)[cell viewWithTag:21];
UILabel *msg = (UILabel *)[cell viewWithTag:22];
UILabel *date = (UILabel *)[cell viewWithTag:23];
UILabel *time = (UILabel *)[cell viewWithTag:24];
valuedate.text=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"offerTitle"];
msg.text=#"How are you?";
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSString *img=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"offerPhoto"];// here i am getting image path
NSURL *url = [NSURL URLWithString:img];
NSData * imageData = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageData];
dispatch_sync(dispatch_get_main_queue(), ^{ //in main thread update the image
cell.imageView.image = image;
cell.textLabel.text = #""; //add this update will reflect the changes
});
});
return cell;
}
EDIT
in order to reuse the downloaded image u can either save them on disk or just for save them some where for example in dictionary for temporary using
in below code i took one example dictionary, and strong the download images with row as key
#interface ViewController ()
{
NSMutableDictionary *imagesDictionary; //lets declare a mutable dictionary to hold images
}
in this method just initialise it
- (void)viewDidLoad {
[super viewDidLoad];
// rest of your code
//...........
//
imagesDictionary = [[NSMutableDictionary alloc]init]; //initilise
}
in index this method just add the downloaded images to dictionary for corresponding row as key
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
__block tablecellTableViewCell *cell= [self.activitiesTableView_ dequeueReusableCellWithIdentifier:tableviewidentifier];
if(cell==nil)
{
cell = [[tablecellTableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:tableviewidentifier];
}
if(indexPath.row == [self tableView:tableView numberOfRowsInSection:indexPath.section] - 1)
{
// [[cell textLabel] setText:#"Load more records"];
}
__block NSString *row = [NSString stringWithFormat:#"%d",indexPath.row]; //add this
UILabel *valuedate = (UILabel *)[cell viewWithTag:21];
UILabel *msg = (UILabel *)[cell viewWithTag:22];
UILabel *date = (UILabel *)[cell viewWithTag:23];
UILabel *time = (UILabel *)[cell viewWithTag:24];
// valuedate.text=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"offerTitle"];
msg.text=#"How are you?";
if(![[imagesDictionary allKeys] containsObject:row]) //if image not found download and add it to dictionary
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
// NSString *img=[[self.inboxmessagesarray objectAtIndex:indexPath.row]objectForKey:#"offerPhoto"];// here i am getting image path
NSURL *url = [NSURL URLWithString:img];
NSData * imageData = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:imageData];
dispatch_sync(dispatch_get_main_queue(), ^{ //in main thread update the image
[imagesDictionary setObject:image forKey:row]; //sorry, while editing to your code i forgot to add this
cell.imageView.image = image;
cell.textLabel.text = #""; //add this update will reflect the changes
NSLog(#"loading and addig to dictionary");
});
});
}
else
{
cell.imageView.image = [imagesDictionary objectForKey:row];
NSLog(#"retriving from dictioary");
}
return cell;
}
First of all you are calling dataWithContentsOfURL: function which will make the app non responsive because you are calling it on main thread. To make it responsive you need to create a custom cell YourCell and declare a method in YourCell.h
#interface YourCell : UITableViewCell
{
UIImage *_cImage;
}
- (void)downloadImageFromURL:(NSURL *)imageUrl;
#end
Now in YourCell.m you need to do like this:
- (void)downloadImageFromURL:(NSURL *)imageUrl
{
if (_cImage != nil)
{
self.imageView.image = _cImage;
}
else
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
_cImage = [UIImage imageWithData:[NSData dataWithContentsOfURL:imageUrl]];
dispatch_sync(dispatch_get_main_queue(), ^{
self.imageView.image = _cImage;
});
});
}
}
Now from cellForRowAtIndexPath: you just need to call downloadImageFromURL: function of YourCell and pass the imageUrl to it and its the cell responsibility to download and show the image.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier= #"YourCell";
YourCell *cell = (YourCell *)[self.activitiesTableView_ dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil)
{
cell = [[[NSBundle mainBundle] loadNibNamed:#"YourCell" owner:self options:nil] objectAtIndex:0];
}
// Set your UILabels as before.....
NSString *imagePath=[[self.inboxmessagesarray objectAtIndex:indexPath.row] objectForKey:#"offerPhoto"];
[cell downloadImageFromURL:[NSURL URLWithString:imagePath]];
return cell;
}
Let me know if you have any questions.
UIImageView *img1 = (UIImageView *)[cell viewWithTag:104];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
dispatch_async(dispatch_get_main_queue(), ^{
img1.image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:img]]];
});
});
Send async requests for images. Doing this would not block your UI until the image gets loaded.

UICollectionView doesn't display any image

I'm trying to display image from documents directory in UICollectionView, everything works fine, but no image appears
- (void)viewDidLoad
{
[super viewDidLoad];
// Initialize recipe image array
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSArray *dirContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:documentsDirectory error:nil];
NSMutableArray *image = [NSMutableArray array];
for (NSString *tString in dirContents) {
if ([tString hasSuffix:#".png"]) {
[image addObject:tString];
listeImages = [NSArray arrayWithArray:image];
}
}
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section{
return listeImages.count;
}
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath{
static NSString *identifier = #"Cell";
UICollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:identifier forIndexPath:indexPath];
UIImageView *listeImageView = (UIImageView *)[cell viewWithTag:100];
UILabel *LabelView = (UILabel *)[cell viewWithTag:110];
LabelView.text = [listeImages objectAtIndex:indexPath.row];
listeImageView.image = [UIImage imageNamed:[listeImages objectAtIndex:indexPath.row]];
NSLog(#" List UIImageView listeImageView.image %#",listeImageView.image);
cell.backgroundColor = [UIColor redColor];
cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"photo-frame.png"]];
NSLog(#" List NSArray *listeImages %#",listeImages);
cell.tag = indexPath.row;
return cell;
}
with this piece of code, displays the correct UICollectionView UILabel well but no image is displayed.
I use this line of code to store my image in listeImageView.image.
UIImageView *listeImageView = (UIImageView *)[cell viewWithTag:100];
listeImageView.image = [UIImage imageNamed:[listeImages objectAtIndex:indexPath.row]];
Here are the results of my NSLog:
2014-10-11 09:46:31.117 imgapp[2803:60b] List NSArray *listeImages; (
"image10102014233607.png",
"image10102014233616.png",
"image10102014233627.png"
)
2014-10-11 09:46:31.158 imgapp[2803:60b] List UIImageView listeImageView.image (null)
2014-10-11 09:46:31.171 imgapp[2803:60b] List UIImageView listeImageView.image (null)
2014-10-11 09:46:31.178 imgapp[2803:60b] List UIImageView listeImageView.image (null)
any help will be appreciated.
Thanks
You have below,
listeImageView.image = [UIImage imageNamed:[listeImages objectAtIndex:indexPath.row]];
But your doing,
cell.backgroundView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:#"photo-frame.png"]];
Why your not using your listeImageView as below:-
cell.backgroundView = listeImageView;
That should get you the image.
UPDATE :-
for (NSString *tString in dirContents) {
if ([tString hasSuffix:#".png"]) {
**[image addObject:[UIImage imageWithContentsOfFile:tString] ]; //Do this as in below line you were not create a image object which you are trying to get.**
//Also check your image array for object, that is it getting stored or not.
// [image addObject:tString];
}
}
listeImages = [NSArray arrayWithArray:image]; //Do this after you have added all objects in your image mutable array and not in for loop as this will initialise it many tiems depending on your loop run count.
You're not adding your listeImageView to anything.
Try it with
[cell addSubview:listeImageView];
or if you really want it to be the backgroundView
cell.backgroundView = listeImageView;
But it'd be much cleaner if you create a custom UICollectionViewCell-class where you can define what content this cell has.
Have u tried to give background color to cell instead of backgroundview.do that once if possible with same code of yours!
Or
You can try like :-UIImageView *listeImageView = (UIImageView *)[cell viewWithTag:100];
[cell bringviewtoFront:listeImageView ];
You'd be much better off subclassing UICollectionViewCell, and setting up the subviews in a storyboard. Your code could be much cleaner this way:
static NSString *kCustomCellIdentifier = #"customcell";
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
MYAPPCustomCollectionViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:kCustomCellIdentifier forIndexPath:indexPath];
// Load custom image
NSString *imageName = [listeImages objectAtIndex:indexPath.row];
if (imageName)
{
UIImage *image = [UIImage imageNamed:imageName];
if (image)
{
cell.customImageView.image = image;
}
else
{
// Set an empty state here
cell.customImageView.image = [UIImage imageNamed:#"errorImage.png"];
}
}
return cell;
}

iOS: UITableView lagging with image data

I have a UITableview that has a list of images like so. But it is very laggy for some reason when I scroll up and down. Any way to stop this? The images dont need to be reloaded. It needs to stay static.
- (UITableViewCell *)tableView:(UITableView *)tableView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *MyIdentifier = #"MyIdentifier";
UITableViewCell *cell = [self.tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault
reuseIdentifier:MyIdentifier];
}
ContentModel *contentModel = [self.tableArray objectAtIndex:indexPath.row];
NSURL *url = [NSURL URLWithString:contentModel.txtImages];
NSData *data = [NSData dataWithContentsOfURL:url];
cell.imageView.image = [[UIImage alloc] initWithData:data];
return cell;
}
You may better use AFNetworking UIImageView Methods:
[imageView setImageWithURL:[NSURL URLWithString:#"http://image.com/image.png"]];
Even with a PlaceHolder:
[self.image setImageWithURL:[NSURL URLWithString:#"http://image.com/image.png"] placeholderImage: [UIImage imageNamed:#"logo"]];
https://github.com/AFNetworking/AFNetworking
This will dramatically reduce the lag on your tableview.
We have very similar requirements but my code works perfectly, I am guessing that
these commands slow down your routine:
NSURL *url = [NSURL URLWithString:contentModel.txtImages];
NSData *data = [NSData dataWithContentsOfURL:url];
cell.imageView.image = [[UIImage alloc] initWithData:data];
instead I use the following:
NSString *icon = CurrentQRCode.parsed_icon;
NSString *filePath = [[NSBundle mainBundle] pathForResource:icon ofType:#"png"];
UIImage *image_file = [UIImage imageWithContentsOfFile:filePath];
cell.imageView.image = image_file;
the whole routine is below:
QRTypeCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[QRTypeCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];}
CurrentQRCode = (QRCode *)[fetchedResultsController objectAtIndexPath:indexPath];
NSString *icon = CurrentQRCode.parsed_icon;
NSString *string = CurrentQRCode.parsed_string;
cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
NSString *filePath = [[NSBundle mainBundle] pathForResource:icon ofType:#"png"];
UIImage *image_file = [UIImage imageWithContentsOfFile:filePath];
cell.imageView.image = image_file;
cell.labelview.text = string;
I believe I originally tried handling UIImages using initWithData but found them a lot slower than the other methods.
Never ever ever ever load data from a network on the main thread. Use GCD or a framework like AFNetworking or restkit. The worst thing you could ever do to you app is lock up your main thread with things that can be computed off the main thread. A good rule of thumb is to ask is this something that is updating the UI, if not think about moving it to another thread.
I would also look at some of the WWDC videos about multithreading and anything related to moving off the main thread if you really want to understand the reasons why.
AFNetworking
RestKit
GCD

Load image into UICollectionVIewCell

Im having problem setting image into UiCollectionViewCell
THis is my code :
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath
{
NSURL * imageURL = [NSURL URLWithString:#"https://mozorg.cdn.mozilla.net/media/img/firefox/firstrun/logo.png?2013-06"];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage * image = [UIImage imageWithData:imageData];
UIImageView * myImageView = [[UIImageView alloc] initWithImage:image];
myImageView.image = [UIImage imageNamed:#"myimg"];//set the image
GLCell *cell = (GLCell *)[collectionView dequeueReusableCellWithReuseIdentifier:CELL_IDENTIFIER forIndexPath:indexPath];
cell.displayString = [NSString stringWithFormat:#"%d user number", indexPath.row];
cell.backgroundColor = [UIColor colorWithPatternImage:[UIImage imageNamed:#"myimg"]];
return cell;
}
the string value shows without problem , but cell have no image.
NSURL * imageURL = [NSURL URLWithString:#"https://mozorg.cdn.mozilla.net/media/img/firefox/firstrun/logo.png?2013-06"];
NSData * imageData = [NSData dataWithContentsOfURL:imageURL];
UIImage * image = [UIImage imageWithData:imageData];
GLCell *cell = (GLCell *)[collectionView dequeueReusableCellWithReuseIdentifier:CELL_IDENTIFIER forIndexPath:indexPath];
cell.displayString = [NSString stringWithFormat:#"%d user number", indexPath.row];
cell.backgroundColor = [UIColor colorWithPatternImage:image]];
You aren't adding the myImageView to your cell. Instead of creating your own UIImageView you could just use the UITableViewCell's imageView property

Resources