UITableViewCell subclass wrong image in cell or old image bug
I recommend you to use 3rd party library to load image with url such as Kingfisher
. It will handle caching and cancel loading for you.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let data = dataSource[indexPath.row]
let cell = tableView.dequeueReusableCell(withIdentifier: "Identifier") as! ACell
cell.update(data)
return cell
}
And the cell will look like this.
import Kingfisher
class ACell: UITableViewCell {
@IBOutlet fileprivate weak var backgroundImageView: UIImageView!
fileprivate func reset() {
backgroundImageView.image = nil
}
func update(_ data: ATypeOfData) {
reset()
let resource = ImageResource(downloadURL: url)
backgroundImageView.kf.setImage(with: resource)
}
}
The reason you are failing is you misunderstood reusing cell.
let updateCell = tableView.cellForRow(at: indexPath)
The updateCell
can be a different cell with a cell which you want to use. It can be just a reused random cell. If you really want to track a cell, you need to set a property and check the property in cellForRowAt
is same as the property in your image loading closure. I really recommend you to use the pattern I attached.
Images in UITableViewCells are loading wrong
The table view cells are being reused for performance reason, so they will retain the previously used image in the UIImageView if you do not set it to anything before you load the image.
Right before you call the startLoadingImageWithUrl, you can set the initial image of the imageView with a placeholder image first or maybe add loading indicator on top of the imageView. But remember to remove the loading indicator when the real image is loaded.
- (void) startLoadingImageWithUrl:(NSString *)urlString forItem:(id)item
{
UIImageView *imageView = ((UIImageView*)[((UIView*)item)viewWithTag:100]);
imageView.image = placeholderImage;
if (self.cacheStoreDictionary[urlString]) {
UIImage *image = self.cacheStoreDictionary[urlString];
[self.delegate lcCachedImageLoader:self didLoadImage:image forItem:item wasCacheHit:YES];
} else {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
UIImage *image = [UIImage imageWithData:data];
dispatch_async(dispatch_get_main_queue(), ^{
[self.cacheStoreDictionary setObject:image forKey:urlString];
[self.delegate lcCachedImageLoader:self didLoadImage:image forItem:item wasCacheHit:NO];
});
});
}
}
And for the image appearing at the wrong cell after the image is loaded, it is because you are passing item, which is reused cell, as a parameter in the startLoadingImage and didLoadImage. Try to pass indexPath instead and locate the correct cell with the indexPath, the update the cell image view.
UITableViewCell *cell = [self.tableView cellForRowAtIndexPath:indexPath];
UITableView cell sometimes fails to update image, but displays fine after scroll
Yup, the problem was on my side.
The exact cause was some pretty weird date comparison code. More precisely, this code was failing to call reloadRowsAtIndexPaths:
with the right indexes because two cells had identical dates, which resulted in one cell getting updated twice, and one cell not getting updated at all. I'm not referring to the code provided in the question.
My advice to anybody else who runs into the same kind of problem is to carefully check the parts of your code that update and create the cells in your table view.
UITableView dequeued cells reloading old images
Here is what I did using SDWebImage, I was forced to use a placeholder for all cells, I just set the ones without images to a small chevron icon. Works as expected. Thanks everybody.
RSSItem * rssItem = (RSSItem *)(_rssParser.rssItems)[indexPath.row];
if (rssItem.imageURL == nil ){
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 20, 20)];
[imageView setImageWithURL:[NSURL URLWithString:rssItem.imageURL] placeholderImage:[UIImage imageNamed:@"chevron.png"]];
cell.accessoryView = imageView;
}else{
UIImageView *imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 110, 96)];
imageView.contentMode = UIViewContentModeScaleAspectFit;
[imageView setImageWithURL:[NSURL URLWithString:rssItem.imageURL] placeholderImage:[UIImage imageNamed:@"loading.png"]];
cell.accessoryView = imageView;
}
[cell.textLabel setText:rssItem.title];
[cell.detailTextLabel setText:rssItem.summary];
return cell;
UITableViewCell image not shown until selected
The problem was that my Image wasn't set on the main thread. To solve the problem, I simply used the following code below which ensured that my image will be set immediately.
dispatch_async(dispatch_get_main_queue(), {
// do image functions here
)}
Loading images asynchronously, wrong image in cell
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.
Related Topics
Converting Local Realms to Synced Realm
How to Cache Cells and Also Reuse Cells in a Collectionview That Has Avplayers Embedded in Each Cell
How to Delay Animation in Swiftui
How to Access Results from a Realm in Swift
Biometric Authentication Evaluation with Swiftui
How to Increment a Swift Int Enumeration
Dynamically Set Properties from Dictionary<String, Any> in Swift
What Do Detached and Assigncurrentcontext Meaning
F# Asynchronous Http Request - Parse JSON Response
Extension for Array Where Element Is Optional
Support Arkit in Lower End Devices
Why Do I Get Rgb Values of (0,0,0) for an Nsimage with a Transparent Background
Using Enumerated with Foreach in Swiftui
Create Record Only If Parent Exists in Vapor Using Fluent
Swift: Switch Statement Fallthrough Behavior