Loading images from a URL into a UITableViewCell's UIImageView - objective-c

I have the following code: (Note: newsImageURL is an NSArray)
NSString *imagesURL = #"http://aud.edu/images/newsimage01.png,http://aud.edu/images/newsimage04.png,http://aud.edu/images/newsimage02.png,http://aud.edu/images/newsimage03.png,http://aud.edu/images/newsimage01.png,http://aud.edu/images/newsimage04.png,http://aud.edu/images/newsimage01.png,http://aud.edu/images/newsimage04.png,http://aud.edu/images/newsimage01.png,http://aud.edu/images/newsimage04.png,";
newsImageURL = [[NSArray alloc] initWithArray:[AllNewsHeadLine componentsSeparatedByString:#","]];
I am trying to load these images into a cell using the code below:
NSData* imageData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString: [newsImageURL objectAtIndex:indexPath.row]]];
cell.image = [UIImage imageWithData:imageData];
The image loads fine when I use this line instead:
cell.image = [UIImage imageNamed:#"imagename.png"];
What am I doing wrong?

You should use an existing framework which supports caching, default place holders and lazy loading of images.
https://github.com/rs/SDWebImage is a good and simple framework
#import "UIImageView+WebCache.h"
...
- (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://aud.edu/images/newsimage01.png,http://aud.edu/images/newsimage04.png"]
placeholderImage:[UIImage imageNamed:#"placeholder.png"]];
cell.textLabel.text = #"My Text";
return cell;
}

You can load data this way:
NSData *data = [NSData dataWithContentsOfURL: [NSURL URLWithString: [newsImageURL objectAtIndex:indexPath.row]]];
And you can instantiate the array of URLs this way too:
NSArray *newsImageURL = [imagesURL componentsSeparatedByString:#","];
However, if someone scrolls around on the table a great deal, you may end up loading the images many times over as the cells are recycled.

Maybe you can have a try https://github.com/SpringOx/ALImageView.git.It is much simpler than SDWebImage.You only need two source files(ALImageView.h/ALImageView.m).You can reuse the image view to reload different urls in a tableview cell.
Support local and memory cache;
Support place holders;
Support tap touch(target-action);
Support corner for the image view;

You Can Easily load all the images with the Help of Following code ,Details Array is a Main Array
Details Array :- {
"item_code" = 709;
"item_desc" = Qweqweqwe;
"item_name" = AQA;
"item_photo" = "http://toshaya.com/webapp/snap&sell/api/img_items/709.png";
"item_price" = "0.00";
"item_till" = "20-25";
"item_type" = Orange;
latitude = "";
longitude = "";
}
With the Help of Following Code Retrieve The Photo-URL into String
NSString * result = [[DetailArray objectAtIndex:indexPath.row]objectForKey:#"item_photo"]; //componentsJoinedByString:#""];
NSLog(#"%#",result);
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:result]];
cell.icon.image = [UIImage imageWithData:imageData];

Related

Collectionview cell images not appearing in the correct order

What I have is an array of url's that point to images and a corresponding array of the names of the images
For example
['www.pictures/dog.jpg', 'www.pictures/lamp.jpg', 'www.pictures/piano.jpg']
['dog', 'lamp', 'piano']
I want each cell to have a the picture with the corresponding word. My problem is that the pictures almost always appear out of order. How I have it now, the words appear in order.
Anyone have an idea of how to get my images appear in order
- (photoCollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
photoCollectionViewCell *photoCell = [collectionView dequeueReusableCellWithReuseIdentifier:#"photoCell" forIndexPath:indexPath];
if(self.photoIndex == (self.totalPhotos)) {
self.photoIndex = 0;
}
NSURL *url = [NSURL URLWithString:self.imageURLArray[self.photoIndex]];
NSString *word = self.phraseWordsArray[self.photoIndex];
photoCell.photoImageView.image = [UIImage imageNamed:#"icn_default"];
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul);
dispatch_async(queue, ^{
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
photoCell.photoImageView.image = image;
photoCell.photoLabel.text = word;
});
});
self.photoIndex++;
return photoCell;
}
When you are using dispatch_queue_t to request data, iOS system would perform the queue randomly since the best performance.
therefore your order is not what you expected.
reference:
https://developer.apple.com/library/prerelease/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/index.html

UITableView: How to load an image only once then use it in all cells

I'm creating an app using the Twitter API and parsing with JSON and every time I load the image into the cells it's taking multiple images and everything runs slowly. How would I go on by getting the image once then put the same image into all cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"TweetCell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
NSDictionary *tweet = [tweets objectAtIndex:indexPath.row];
NSString *text = [tweet objectForKey:#"text"];
NSString *time = [tweet objectForKey:#"created_at"];
time = [time stringByReplacingOccurrencesOfString:#" +0000 "withString:#"/"];
NSString *twitterImage = [[tweet objectForKey:#"user"] objectForKey:#"profile_image_url_https"];
NSString *completeImage = [NSString stringWithFormat:#"%#", twitterImage];
NSData * imageData = [[NSData alloc] initWithContentsOfURL: [NSURL URLWithString: completeImage]];
imageLabel.image = [UIImage imageWithData: imageData];
cell.imageView.image = [UIImage imageWithData: imageData];
cell.textLabel.text = text;
cell.textLabel.numberOfLines = 3;
cell.detailTextLabel.text = [NSString stringWithFormat:#"%#", time];
}
return cell;
}
Looks like this right now but really laggy when I scroll.
http://gyazo.com/8ab8325f3921fdb7e4f0ea0107d389ac.png
Looks to me like the problem is in these lines:
NSDictionary *tweet = [tweets objectAtIndex:indexPath.row];
NSString *twitterImage = [[tweet objectForKey:#"user"] objectForKey:#"profile_image_url_https"];
I believe that is getting a new copy of the image for each cell. Each indexPath.row is a new tweet, thus you are getting multiple twitterImage
You should use cache for images. I hope this link helps you:
http://khanlou.com/2012/08/asynchronous-downloaded-images-with-caching/
If it's always the same picture, load it before the table's loading in a class parameter (for example in the viewDidLoad) and always use this parameter.
If it's dynamic, load the image in the background using performSelectorInBackground.
The problem that you are facing is because you are downloading all the images on the main thread.
To solve this either :
Download images using a separate thread using NSOperationQueue.
A good tutorial on the same : http://www.raywenderlich.com/19788/how-to-use-nsoperations-and-nsoperationqueues
Use this class 'AsyncImageView'. I have used this and it works fine. So, instead of UIImageView you will need to use the class AsyncImageView and this library will manage the downloading for you asynchronously.
https://github.com/nicklockwood/AsyncImageView

How to fix a slow scrolling table view

I have a table view that's scrolling slowly. Does anyone know why that might be?
There is an image for each row, but even after the images are loaded it still stutters and scrolls slowly.
thanks for any help
here's my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *simpleTableIdentifier = #"SimpleTableCell";
SimpleTableCell *cell = (SimpleTableCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier];
if (cell == nil)
{
NSArray *nib = [[NSBundle mainBundle] loadNibNamed:#"SimpleTableCell" owner:self options:nil];
cell = [nib objectAtIndex:0];
}
// Get item from tableData
NSDictionary *item = (NSDictionary *)[displayItems objectAtIndex:indexPath.row];
// display the youdeal deal image
photoString = [item objectForKey:#"image"];
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:photoString]]];
cell.titleLabel.text = [item objectForKey:#"supercat"];
cell.descriptionLabel.text = [item objectForKey:#"title"];
NSString *convertedLeftCount = [NSString stringWithFormat:#"%#",[item objectForKey:#"left_count"]];
cell.amountLabel.text = convertedLeftCount;
cell.thumbnailImageView.image = image;
cell.priceLabel.text = [item objectForKey:#"cat"];
return cell;
}
It's due to the image loading mechanism you used.
You are loading the image from url in the main thread. That's why the UI is blocked for some time also the dataWithContentsOfURL: is a synchronous call. So the UI will respond after getting the image data.
Apple states that the time taking processes like webrequest,parsing huge data etc must be done on other threads rather than main thread.
And all UI related tasks must be done on main thread.
Solutions:
Request the image in background thread, not in main thread.
Cache the image once you get it
Source code and Third Party Libraries
Here are some links which will help you to understand the basic idea of loaing image using asynchronous methods
LazyTableImages
HJCache
SDWebImage
The images are getting loaded every time a cell is loaded, because the imageWithData: doesn't use any cache.
Edit: I saw a comment that suggests loading images asynchronously. You already have your custom class for each cell so it should be easy to do it. If it were an answer I'd vote it up
I think You are trying to say this.
NSURL* url = [NSURL URLWithString:#"http://www.YourImageUrl.com"];
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];
// Now workout with the image
}
}];
This will make the asynchronous call, and load the images after tableview loaded i.e when the image load complete the image will show but the table will be loaded when the table view is needed to load.

Images from URLs (RSS Reader) displaying in table view - problem

I'm having a problem with a table view and some custom cells. Here is my code:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSLog(#"cellForRowAtIndexPath");
static NSString *MyIdentifier = #"customCell";
EventTableCell *cell = (EventTableCell *)[tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
//cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
[[NSBundle mainBundle] loadNibNamed:#"EventTableCell" owner:self options:nil];
cell = self.eventCell;
}
//Set up the cell
int storyIndex = [indexPath indexAtPosition: [indexPath length] - 1];
[[cell eventNameLabel] setText:[[stories objectAtIndex: storyIndex] objectForKey: #"title"]];
[[cell eventDateLabel] setText:[[stories objectAtIndex: storyIndex] objectForKey: #"date"]];
NSString * storyLink = [[stories objectAtIndex: storyIndex] objectForKey: #"link"];
// clean up the link - get rid of spaces, returns, and tabs...
storyLink = [storyLink stringByReplacingOccurrencesOfString:#" " withString:#""];
storyLink = [storyLink stringByReplacingOccurrencesOfString:#"\n" withString:#""];
storyLink = [storyLink stringByReplacingOccurrencesOfString:#" " withString:#""];
//NSString *string = [[NSString alloc] stringWithString:[[stories objectAtIndex: storyIndex] objectForKey: #"link"]];
NSURL *url = [NSURL URLWithString:storyLink];
NSData *data = [[NSData alloc] initWithContentsOfURL: url];
UIImage *image = [UIImage imageWithData: data];
[[cell eventImage] setImage:image];
return cell;
}
My table has a lot of these custom cells in it, more than the view can show at once. So therefore I need to scroll up/down to see all the cells. My problem is this, when I scroll it lags a lot and in the debugger console it calls cellForRowAtIndexPath as each new cell comes into the view. Each cell holds an image which is downloaded from a URL and hence has to be converted to a UIImage. I believe this is whats causing the lag.
Can anyone direct me as to what I need to do in order to download the images and have them display in the cells without causing major lag in the app?
IE: Where would I put the download/conversion code so that the image is already stored as an image before the cell needs to be dispayed?
Thanks,
Jack
If you want to pre-download the images, you could do it at any point in your application and cache them for later. For example, you could start the downloads just after you download and parse the RSS feed. You can save them in the directory returned by [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0]. It would be best to use asynchronous method to download them, and have just a few downloads active at a time for best performance.
If you want to load them as needed, set a placeholder image when you allocate the cell and use an asynchronous NSURLConnection or the like to do the download. Once the download completes, replace the placeholder with the real image (and cache it for reuse later, of course).

Youtube Videos in tableview cells

I currently have a tableview with YouTube videos embedded inside of the custom cells.
I did this because from my research it seemed like the only way to allow the videos to load without leaving my application.
The problem is this
The thumbnails take a while to load. As I scroll down the list of videos, it keeps having to load the thumbnails. If I scroll back up, it tries to load the video thumbnails yet again.
Has anyone got any suggestions on either better ways of doing this, or ways of getting the table cells to keep the data and not replace it?
My code looks like this:
-(UITableViewCell *)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath{
static NSString *MyIdentifier = #"MyIdentifier";
YouTubeCell *cell = (YouTubeCell*)[tableView dequeueReusableCellWithIdentifier:MyIdentifier];
if(cell ==nil){
cell = [[[YouTubeCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier] autorelease];
}
NSDictionary *dic = [youTubeArr objectAtIndex:indexPath.row];
[cell updateCellData:dic];
return cell;
}
-(void)updateCellData:(NSDictionary*)dict
{
NSDictionary *tempDic = [dict objectForKey:#"video"];
self.titleLbl.text = [tempDic objectForKey:#"title"];
NSString *viewCountStr = [NSString stringWithFormat:#"%# views -",[tempDic objectForKey:#"viewCount"]];
viewCountLbl.text = viewCountStr;
uploadedDateLbl.text = [tempDic objectForKey:#"uploaded"];
NSDictionary *videoDic = [tempDic objectForKey:#"player"];
NSString *videoStr = [NSString stringWithFormat:#"%#",[videoDic objectForKey:#"default"]];
NSString *embedHTML =
#"<html><head>\
<body style=\"margin:0\">\
<embed id=\"yt\" src=\"%#\" type=\"application/x-shockwave-flash\" \
width=\"%0.0f\" height=\"%0.0f\"></embed>\
</body></html>";
// videoView = [[UIWebView alloc] initWithFrame:CGRectMake(3, 5, 100, 60)]; initialzed in ///initwithstyle of cell
NSString *html = [NSString stringWithFormat:embedHTML, videoStr, videoView.frame.size.width, videoView.frame.size.height];
[videoView loadHTMLString:html baseURL:nil];
}
You should cache your loaded images.
One approach could be to create for example a mutable dictionary, in which you store your images with keys unique to your UITableViewCells. In cellForRowAtIndexPath you retrieve the corresponding image by calling for example [dictionary objectForKey:uniquecellidentifier]. If it returns nil, you know the image has not yet been loaded and you should create a request to do so. As soon as the loading has finished, you store the image in the dictionary ([dictionary setObject:image forKey:uniquecellidentifier]
This should get you a more specific idea:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];
}
NSString *cellid=[NSString stringWithFormat:#"Cell%i%i", indexPath.section, indexPath.row];
if([dictionary objectForKey:cellid]){
NSLog(#"Retrieving value for %#: %#", cellid, [dictionary objectForKey:cellid]);
cell.textLabel.text=[dictionary objectForKey:cellid];
//Show image from dictionary
}else{
NSLog(#"Now value set for %#.", cellid);
[dictionary setObject:[NSString stringWithFormat:#"Testvalue%#", cellid] forKey:cellid]; //Save image in dictionary
cell.textLabel.text=#"Loaded";
}
return cell;
}
Create an NSMutableDictionarynamed "dictionary" in your header file and initialize it in viewDidLoad:
dictionary = [[NSMutableDictionary alloc] init];
Header file:
NSMutableDictionary *dictionary;
This will result in the following behaviour:
The first time, your cell is displayed, it shows "Loaded". In all subsequent appearances it will display its set value.