Caching UITableViewCells - ios

I have a view with UITableView in it which can display 4 typles of UITableViewCell's (custom ones). Basically, two of them are with media (image, move, sound) and 2 of them have additionally users avatars.
Let's generalize that cells with media will display only images (thumbnails). Of course those images are dynamically downloaded when cell is created. It could be harmful to download those images everytime user scrolls the table view so I use EGOCache to cache those images but... This ain't helping with scrolling issues!! I thought that caching will store pionter to those images but everytime cell is recreated it takes this image from disk (so Intruments are telling me that this method is killing my performace).
My question is: How to cache UITableViewCell so it's not created everytime I scroll UITableView a little bit?
Here are samples from my code so you can imagine point of my question:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
Event *event = [self.events objectAtIndex:indexPath.row];
if ([event.type isEqualToString:#"camp"]) {
if (!event.mediaType) {
CampCell *cell = [self.tableView dequeueReusableCellWithIdentifier:[CampCell identifier]];
[cell configureWithModel:event];
return cell;
} else {
CampMediaCell *cell = [self.tableView dequeueReusableCellWithIdentifier:[CampMediaCell identifier]];
[cell configureWithModel:event];
return cell;
}
} else {
if (!event.mediaType) {
StatusCell * cell = [self.tableView dequeueReusableCellWithIdentifier:[StatusCell identifier]];
[cell configureWithModel:event];
return cell;
} else {
StatusMediaCell *cell = [self.tableView dequeueReusableCellWithIdentifier:[StatusMediaCell identifier]];
[cell configureWithModel:event];
return cell;
}
}
}
And this is how configureWithModel: looks like:
- (void)configureWithModel:(id)model {
if ([model isKindOfClass:[Event class]]) {
Event *event = model;
self.titleLabel.text = event.title;
self.locationLabel.text = event.address;
self.timeLabel.text = [self hoursLeftToDate:event.expirationDate];
UIImageView *imageAttachedToStatus = [[UIImageView alloc] initWithFrame:CGRectMake(0.0, 0.0, self.mediaContainerView.frame.size.width, self.mediaContainerView.frame.size.height)];
imageAttachedToStatus.contentMode = UIViewContentModeScaleAspectFill;
imageAttachedToStatus.clipsToBounds = YES;
[self getMediaAttachmentForModel:model completion:^(id attachment) {
if (attachment) {
imageAttachedToStatus.image = (UIImage *)attachment;
}
}];
[self.mediaContainerView addSubview:imageAttachedToStatus];
}
}
And, of course, you may wonder how getMediaAttachmentForModel:completion: looks like...
- (void)getMediaAttachmentForModel:(Event *)model completion:(void (^)(id attachment))completion {
NSString *mediaID = [NSString stringWithFormat:#"media%li", (long)model.eventID];
if ([[EGOCache globalCache] hasCacheForKey:mediaID]) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
id cachedAttachment =[[EGOCache globalCache] objectForKey:mediaID];
dispatch_async(dispatch_get_main_queue(), ^{
completion(cachedAttachment);
});
});
} else {
[[Client sharedClient] fetchMediaThumbnailForEvent:model completion:^(id attachment, NSError *error) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[[EGOCache globalCache] setObject:attachment forKey:mediaID];
dispatch_async(dispatch_get_main_queue(), ^{
completion(attachment);
});
});
}];
}
}

The proper solution would be to find/implement a cache that is able to cache images in memory, without fetching them from disk every time.
Take a look at Path's FastImageCache

Related

Load more UICell in the bottom of the UITableView

I started an iOS project and I'm working with UITableView to display a list of pilots with images . I did pagination on my api and I tried to load more once you scrolled the tableview. the problem that I got is that the new cells are always displayed on top of the tableview not in the bottom. Please check on my code if there is a solution I will be grateful
- (void)loadData :(NSInteger)page {
MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
url = [NSURL URLWithString:[NSString stringWithFormat:#"%#%#%#%ld",NSLocalizedString(#"get_pilots",nil),mainDelegate.idAccount,#"?page=",(long)page]];
task = [restObject GET:url :mainDelegate.token completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSMutableDictionary* jsonResponse = [NSJSONSerialization
JSONObjectWithData:data
options:kNilOptions
error:nil];
NSArray *pilotKey = [jsonResponse objectForKey:#"pilot"];
for (NSDictionary *pilotItem in pilotKey ){
PilotObject *pilotObj = [PilotObject new];
[pilotObj getPilot:pilotObj :pilotItem];
[_pilotsAll addObject:pilotObj];
}
dispatch_async(dispatch_get_main_queue(), ^{
[hud hideAnimated:YES];
[self checkTableView:_pilotsDisplay :self.view];
[viewPilots.tableViewPilots reloadData];
});
}];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
if (currentPage == totalPages) {
return [_pilotsDisplay count];
}
return [_pilotsDisplay count] + 1;
}
- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == [_pilotsDisplay count] - 1 && currentPage<totalPages ) {
[self loadData:++currentPage];
NSLog(#"current page : = %ld",(long)currentPage);
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (indexPath.row == [_pilotsDisplay count]) {
static NSString *identifier = #"PilotCellTableViewCell";
PilotCellTableViewCell *cell = (PilotCellTableViewCell *)[tableView dequeueReusableCellWithIdentifier:identifier];
cell.hidden=YES;
UIActivityIndicatorView *activityIndicator = (UIActivityIndicatorView *)[cell.contentView viewWithTag:100];
[activityIndicator startAnimating];
return cell;
} else {
PilotObject *pilotObjDisplay = nil;
pilotObjDisplay = [_pilotsDisplay objectAtIndex:[_pilotsDisplay count]-1-indexPath.row];
static NSString *identifier = #"PilotCellTableViewCell";
PilotCellTableViewCell *cell = (PilotCellTableViewCell *)[tableView dequeueReusableCellWithIdentifier:identifier];
cell.hidden=NO;
cell.image.image = pilotObjDisplay.imageDisplayPilot;
cell.titleLabel.text = pilotObjDisplay.firstName;
cell.subTitleLabel.text = pilotObjDisplay.lastName;
cell.backgroundColor = [UIColor colorWithHexString:NSLocalizedString(#"gray_background", nil)];
return cell;
}
return nil;
}
Why you are taking 2 array _pilotsDisplay and _pilotsAll ?
If not necessary then you can also do pagination using one NSMutableArray which you can use in both cases while fetching data from server as well as while filling data to UITableView.
Remember one thing only initialise your NSMutableArray in viewDidLoad method. And when you received new data use addObject method of NSMutableArray which you are already using. And then call reloadData method of UITableView.
And in cellForRowAtIndexPath don't use calculation like [_pilotsDisplay count]-1-indexPath.row, simply use indexPath.row.
Here, inserting rows to the tableview may help you.
[tableView beginUpdates];
NSArray *paths = [NSArray arrayWithObject:[NSIndexPath indexPathForRow:[dataArray count]-1 inSection:1]];
[[self tableView] insertRowsAtIndexPaths:paths withRowAnimation:UITableViewRowAnimationTop];
[tableView endUpdates];
You shouldn't add cells to a tableview. what you should do is add data to the tableview's datasource (in your case, _pilotsDisplay) and then simply reload the table. If you want the new data to appear at bottom or in any particular order, you should do that to your datasource (the array).

Loading images asynchronously, wrong image in cell

I have a UICollectionView in which I am loading multiple images into. From what Ive been reading, in order to match the correct image to each cell I need to subclass UIImageView and get the image there. Because every time I collectionView reloadData, some images duplicate and they are all out of order. But I am unsure how to do this and haven't found any tutorials. I am using Parse for a database.
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
albumImageCell *cell = (albumImageCell *) [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[albumImageCell alloc]init];
}
PFObject *temp = [_dataArray objectAtIndex:indexPath.row];
PFFile *file = [temp objectForKey:#"imageThumbnail"];
if (![cell.hasImage isEqualToString:#"YES"]) {
dispatch_async(imageQueue, ^{
NSData *data = [file getData];
if (data) {
UIImage *image = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^(void){
cell.imageView.image = image;
cell.hasImage = #"YES";
});
}
});
}
return cell;
}
One way to solve this is to re-query the collection view for the cell again once you're back on the main queue. This code should work:
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
albumImageCell *cell = (albumImageCell *) [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[albumImageCell alloc]init];
}
PFObject *temp = [_dataArray objectAtIndex:indexPath.row];
PFFile *file = [temp objectForKey:#"imageThumbnail"];
if (![cell.hasImage isEqualToString:#"YES"]) {
dispatch_async(imageQueue, ^{
NSData *data = [file getData];
if (data) {
UIImage *image = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^(void){
// cellAgain will be the actual cell at that index path, if it is visible.
// If it is not visible, cellAgain will be nil.
albumImageCell *cellAgain = [collectionView cellForItemAtIndexPath:indexPath];
cellAgain.imageView.image = image;
cellAgain.hasImage = #"YES";
});
}
});
}
return cell;
}
I made a small 'tutorial' in answer to a this question. Although the question refers to Core Data, my answer applies to any data source so you should be able to fit it around your use case.
One thing you want to watch out for is the inner block, when you get back onto the main queue. Given that you have no idea how long it takes to get to that point, the cell may no longer be relevant to that image (could have been reused), so you need to do a couple of additional checks...
(a) is the image still required?
if ([[tableView indexPathsForVisibleRows] containsObject:indexPath])
(b) is that cell is the correct cell for the image?
UITableViewCell * correctCell = [self.tableView cellForRowAtIndexPath:indexPath];
Although this tutorial is still valid, I tend to abstract things further these days. As the viewController has to deal with thread-unsafe entities like UIKit and Core Data, it is a good idea to keep all viewController code on the main thread. Background queue abstractions should take place at a lower level, preferably in the model code.
What I ended up doing was subclassing UIImaveView and then passing the image file in cellForRow
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
albumImageCell *cell = (albumImageCell *) [collectionView dequeueReusableCellWithReuseIdentifier:reuseIdentifier forIndexPath:indexPath];
if (cell == nil) {
cell = [[albumImageCell alloc]init];
}
PFObject *temp = [_dataArray objectAtIndex:indexPath.row];
PFFile *file = [temp objectForKey:#"imageThumbnail"];
[cell.imageView setFile:file];
return cell;
}
And then in the customImageView -
- (void) setFile:(PFFile *)file {
NSString *requestURL = file.url; // Save copy of url locally (will not change in block)
[self setUrl:file.url]; // Save copy of url on the instance
self.image = nil;
[file getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
UIImage *image = [UIImage imageWithData:data];
if ([requestURL isEqualToString:self.url]) {
[self setImage:image];
[self setNeedsDisplay];
}
} else {
NSLog(#"Error on fetching file");
}
}];
}
But this gets Data every time the user scrolls to a new cell. So Im still trying to figure out how to match a particular image to a cell, without getting data every time.

Slow iOS Share Extension

I'm working on a sharing extension to simply grab a link, choose a few names to share it to, and Share. The data layer isn't added yet, only the UI to display some names in a tableview (using a custom cell) and I'm pulling in the shared URL from the extension context. All of the code in the VC is below. All views are set up in the Storyboard. Two UIButtons, Two UILabels, One TableView and a UIView to hold it all, so I can easily round the corners.
The issue I'm having is that the _linkLabel that I'm using the display the URL doesn't visually update for nearly 10 seconds! What.In.The.World. What I'm a doing here that's causing this?
I'm logging out the URL in the callback from hasItemConformingToTypeIdentifier and it happens as soon as the extension appears, but doesn't update the label??!! Helps. Please.
#import "ShareViewController.h"
#import "UserCell.h"
#interface ShareViewController ()
#end
#implementation ShareViewController
- (void)viewDidLoad{
self.view.alpha = 0;
_friends = [#[#"Ronnie",#"Bobby",#"Ricky",#"Mike"] mutableCopy];
_containerView.layer.cornerRadius = 6.f;
_selectedIndexPaths = [[NSMutableArray alloc] init];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[UIView animateWithDuration:0.5 animations:^{
self.view.alpha = 1;
}];
}
- (void)viewDidAppear:(BOOL)animated{
//pull the URL out
NSExtensionItem *item = self.extensionContext.inputItems[0];
NSItemProvider *provider = item.attachments[0];
if ([provider hasItemConformingToTypeIdentifier:#"public.url"]) {
[provider loadItemForTypeIdentifier:#"public.url" options:nil completionHandler:^(id<NSSecureCoding> item, NSError *error) {
NSURL *url = (NSURL*)item;
_linkLabel.text = url.absoluteString;
NSLog(#"Link: %#", url.absoluteString);
}];
}
else{
NSLog(#"No Link");
}
}
#pragma mark - UITableView Delegate Methods
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath{
UserCell *cell = (UserCell*)[tableView cellForRowAtIndexPath:indexPath];
if([_selectedIndexPaths containsObject:indexPath]){
[_selectedIndexPaths removeObject:indexPath];
cell.selected = NO;
}
else{
cell.selected = YES;
[_selectedIndexPaths addObject:indexPath];
}
NSLog(#"Share to %i friends", (int)[_selectedIndexPaths count]);
}
-(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
//Later, calc height based on text in comment
return 44;
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [_friends count];
}
-(UITableViewCell*)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
static NSString *CellIdentifier = #"UserCell";
UserCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if(cell == nil){
cell = [[UserCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
cell.selected = ([_selectedIndexPaths containsObject:indexPath]) ? YES : NO;
cell.nameLabel.text = [_friends objectAtIndex:indexPath.row];
return cell;
}
- (IBAction)dismiss {
[UIView animateWithDuration:0.34 animations:^{
self.view.alpha = 0;
} completion:^(BOOL finished) {
[self.extensionContext completeRequestReturningItems:nil completionHandler:nil];
}];
}
#end
Delays in updates to UI elements is a classic sign of trying to update the UI from outside the main queue. Which is what is happening here. You have this:
[provider loadItemForTypeIdentifier:#"public.url" options:nil completionHandler:^(id<NSSecureCoding> item, NSError *error) {
NSURL *url = (NSURL*)item;
_linkLabel.text = url.absoluteString;
NSLog(#"Link: %#", url.absoluteString);
}];
Except that NSItemProvider does not guarantee that the completion handler will be called on the same queue that you started on. You're almost guaranteed to be on a different queue here, so you're getting this weird delay. You need to dispatch back to the main queue to perform the update:
[provider loadItemForTypeIdentifier:#"public.url" options:nil completionHandler:^(id<NSSecureCoding> item, NSError *error) {
dispatch_async(dispatch_get_main_queue(), ^{
NSURL *url = (NSURL*)item;
_linkLabel.text = url.absoluteString;
NSLog(#"Link: %#", url.absoluteString);
});
}];

UITableView Scroll Lags with Parse Images

I've seen several other threads on this, but none using Parse. We have 3 things going on. First, the TableView that lags when it scrolls. Second, the custom cell with the images and labels. And finally, the ParsePull class that fetches the data. We made a separate class for this to use it for other ViewControllers.
I'm pretty sure the problem is fetching each image every time the cell appears on the screen, but I don't know how to fix it. Below is the related code for each one.
UITableView with the following method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
if (!self.eventData.count) {
ParallaxEventCell *loadCell = (ParallaxEventCell *)[tableView dequeueReusableCellWithIdentifier:#"loadingCell" forIndexPath:indexPath];
return loadCell;
} else{
ParallaxEventCell *cell = (ParallaxEventCell *)[tableView dequeueReusableCellWithIdentifier:#"eventCell" forIndexPath:indexPath];
//load an event cell
[cell setUpEvent:[self.eventData objectAtIndex:indexPath.row]];
return cell;
}
}
ParallaxEventCell:
-(void)setUpEvent:(id)event{
self.clipsToBounds = YES;
self.titleLabel.text = [event objectForKey:#"eventTitle"];
self.venueNameLabel.text = [event objectForKey:#"eventVenue"];
self.priceLabel.text = [event objectForKey:#"eventPrice"];
self.customDateLabel.text = [self dateStringFromDate:[event objectForKey:#"eventDate"]];
self.eventURL = [event objectForKey:#"urlString"];
self.geoPoint = [event objectForKey:#"GeoPoint"];
self.descriptionText = [event objectForKey:#"eventDescription"];
[ParsePull picturefromFile:[event objectForKey:#"eventImage"] withCompletion:^(UIImage *returnedImage) {
self.customImageView.clipsToBounds = NO;
self.customImageView.image = returnedImage;
NSLog(#"setUpEvent");
}];
}
- (void)setImage:(UIImage *)image
{
// Store image
self.customImageView.image = image;
// Update padding
[self setImageOffset:self.imageOffset];
}
ParsePull
+(void)picturefromFile:(PFFile *)file withCompletion:(PictureBlock)logo{
NSLog(#"pictureFromFile");
[file getDataInBackgroundWithBlock:^(NSData *data, NSError *error) {
if (!error) {
logo([UIImage imageWithData:data]);
}
else{
logo(nil);
}
}];
}

Using AFNetworking to update a UITableViewCell once a download is complete

Within our app we have a free magazine that users can download in PDF format. If they have not downloaded an issue, that UITableViewCell image has a low alpha so that the user can see that it is not downloaded.
If you tap a cell it will start to download using an AFHTTPRequestOperation and once complete you can view the PDF using QuickLook.
The problem I am having is, when the user initiates the download, then scrolls away and then back, the UITableViewCell that they tapped somehow loses reference that it was downloading and therefore doesn't update the UIProgressView or change the alpha to 1.0 when the download is finished. I cannot for the life of me figure out why [[tableView indexPathForCell:cell] isEqual:indexPath] is not equaling:
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
PUCViewpointItem *item = [self.items objectAtIndex:indexPath.row];
// Check to see if we are already on the row that is activated
if (indexPath.row == self.selectedIndexPath.row) {
// File Path
NSString *path = [self itemPath:item];
// Should we read the issue
if (item.isDownloaded && path) {
item.downloadPath = path;
[self readIssue:item];
return;
}
// TableView Cell
PUCViewpointTableViewCell *cell = (PUCViewpointTableViewCell *)[tableView cellForRowAtIndexPath:indexPath];
if (!path) {
Utility *utility = [[Utility alloc] init];
NSURLRequest *request = [NSURLRequest requestWithURL:item.url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
NSString *localPath = [[utility localDirectory] stringByAppendingFormat:#"/%#.pdf", item.name];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:localPath append:NO];
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
float totalProgress = (float)totalBytesRead/totalBytesExpectedToRead;
if ([[tableView indexPathForCell:cell] isEqual:indexPath]) {
cell.progressView.hidden = NO;
cell.progressView.progress = totalProgress;
item.isDownloading = YES;
item.isDownloaded = NO;
item.progress = totalProgress;
}
}];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if ([[tableView indexPathForCell:cell] isEqual:indexPath]) {
cell.fullImage.alpha = 1.0f;
cell.progressView.hidden = YES;
item.isDownloaded = YES;
item.isDownloading = NO;
}
NSLog(#"%d == %d", [tableView indexPathForCell:cell].row, indexPath.row);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if ([[tableView indexPathForCell:cell] isEqual:indexPath]) {
cell.progressView.hidden = YES;
item.isDownloading = NO;
item.isDownloaded = NO;
}
}];
[operation start];
}
return;
}
NSIndexPath *oldIndexPath = self.selectedIndexPath;
self.selectedIndexPath = indexPath;
[tableView beginUpdates];
[tableView endUpdates];
// Which way are we scrolling?
UITableViewScrollPosition position;
if (indexPath.row == 0 || (oldIndexPath && oldIndexPath.row < indexPath.row)) {
position = UITableViewScrollPositionTop;
} else {
position = UITableViewScrollPositionBottom;
}
[self.tableView scrollToRowAtIndexPath:indexPath atScrollPosition:position animated:YES];
}
If I start a download, then scroll down in my tableView, my NSLog statement will log something like 3 == 10 which makes no sense.
Any ideas how I can fix this?
I was curious about your case so I wrote a little test project, you can find it here: https://github.com/mrojas/MRTableViewTest
Basically, the way to solve it was:
Put the logic to download an item, in the item class
Make the cell be the delegate of the item, to be notified about progress/completion
When cells are scrolled (reused), setting the item on them is enough. They figure the current status and set themselves to be delegates.
Check the project, try it, and let me know if you have doubts.
I didn't use AFNetworking but instead simulated some task that takes 10 seconds to complete, in 2 seconds interval.
I think you have to store somewhere (like an NSMutableArray instance variable) the indexPath you are downloading. so you can do something like that :
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
if( [indexArray indexOfObject:indexPath] != NSNotFound )
{
// alpha for downloading
}
}
In your AFNetworking completion blocks you should remove this indexPath from you indexArray.
As comments said, cells are not reliable for storing any kind of information as they are reallocated when you scroll
#interface ViewController ()
{
NSMutableArray *_indexArray;
}
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UITableView *table = [[UITableView alloc] initWithFrame:self.view.frame style:UITableViewStylePlain];
table.delegate = self;
table.dataSource = self;
_indexArray = [#[] mutableCopy];
[self.view addSubview:table];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
{
return 50;
}
// called when you scroll to new cells or when reloadData is called
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath;
{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"default"];
cell.textLabel.textColor = [UIColor blueColor];
// red color if I'm downloading, else blue
if ([_indexArray indexOfObject:indexPath] != NSNotFound) {
cell.textLabel.textColor = [UIColor redColor];
}
cell.textLabel.text = #"cell in the table";
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath;
{
[_indexArray addObject:[indexPath copy]];
NSLog(#"downloading...");
UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath];
cell.textLabel.textColor = [UIColor redColor]; // update UI temporary (until scroll)
// HD Image so I can scroll up and down for testing
NSString *res = #"http://res.cloudinary.com/******/image/upload/*****/Motorola_Razr_HD_Cam_Sample_7_ftzrj0.jpg";
// custom class for download
[[PLSApi api] downloadDataAtURL:[NSURL URLWithString:res] withBlock:^(NSData *data) {
// download complete
[_indexArray removeObject:indexPath];
cell.textLabel.textColor = [UIColor blueColor]; // update UI
NSLog(#"finished...");
}];
}

Resources